Keywords: Spatial Error, Spatial Lag, Geographically Weighted
Regression, Global & Local Moran’s I, Akaiki Information Criterion,
Schwarz Criterion, Log Likelihood, Likelihood Ratio Test
Introduction
Philadelphia’s housing market has undergone significant
transformations in recent years, with rising property values creating
urgent concerns for urban planners, policymakers, and residents alike.
This upward trend has intensified issues of housing affordability,
disproportionately impacting low- and middle-income households. The
rapid increase in housing values has spurred gentrification, displacing
long-term residents and reshaping the socio-economic fabric of various
neighborhoods across the city. As researchers have observed,
gentrification often leads to social displacement, exacerbating
inequality as housing affordability declines (Freeman & Braconi,
2004; Atkinson, 2004). Understanding the factors driving these shifts in
property values is essential for addressing affordability challenges,
promoting neighborhood stability, and fostering equitable development in
Philadelphia (Lees, 2008).
In a previous study, Ordinary Least Squares (OLS) regression was
employed to explore the relationships between median house values, the
dependent variable, and several key socio-economic predictors. These
predictors included educational attainment, vacancy rates, the
proportion of detached single-family homes, and poverty levels. Each
variable was chosen for its established influence on housing markets and
its ability to shed light on underlying socio-economic conditions that
may shape property values. For instance, educational attainment is
positively associated with economic prosperity and housing demand, as
areas with higher educational levels often benefit from higher incomes
and greater investment Vacancy rates, on the other hand, are typically
linked to neighborhood decline and reduced property values, as vacant
properties signal economic distress, discourage investment, and may
contribute to higher crime rates (Mallach, 2018). The housing market
preference for single-family homes, which offer greater space and
privacy, is well-documented in the literature (Glaeser & Gyourko,
2018), while research consistently demonstrates a negative correlation
between poverty levels and housing values, with higher poverty rates
often linked to decreased demand and underinvestment in local
infrastructure (Galster, 2008).
Although OLS regression provides a foundational understanding of
these relationships, it has limitations when applied to spatial data, as
it assumes independence between observations and ignores potential
spatial dependencies. Housing values in one area are often influenced by
those in nearby areas, resulting in spatial autocorrelation that can
lead to biased or misleading results when using traditional OLS methods.
Spatial autocorrelation reflects Tobler’s First Law of Geography, which
states that “everything is related to everything else, but near things
are more related than distant things” (Tobler, 1970). When spatial
dependencies are ignored, as is the case in OLS regression, the
estimates may suffer from omitted variable bias, yielding inaccurate
conclusions about the relationships between variables (Anselin,
1988).
To address these limitations, this report applies spatial econometric
techniques, specifically spatial lag, spatial error, and geographically
weighted regression (GWR) models, to more accurately capture the spatial
dependencies affecting housing values in Philadelphia. The spatial lag
model incorporates the influence of neighboring values directly into the
regression, allowing for an understanding of how housing values in one
area may affect those in adjacent areas (LeSage & Pace, 2009). The
spatial error model accounts for spatial autocorrelation in the
residuals, isolating unobserved spatially correlated factors that may
influence housing values (Anselin, 1988). Lastly, the geographically
weighted regression (GWR) model offers a localized perspective, allowing
coefficients to vary by location and capturing the heterogeneity of
relationships across different neighborhoods (Brunsdon, Fotheringham,
& Charlton, 1996). By employing these spatial techniques, this study
aims to enhance the accuracy of the initial OLS findings and provide a
more comprehensive understanding of the socio-economic and spatial
factors influencing housing values. These insights will support more
effective policy interventions and urban development strategies aimed at
achieving equitable and sustainable growth in Philadelphia.
Methods
Spatial Autocorrelation
The First Law of Geography, proposed by Waldo Tobler, states that
“everything is related to everything else, but nearer things are
more related than distant things.” This law captures the principle
of spatial dependence, which underpins many spatial analyses, including
spatial regression models. One way to measure spatial dependence is
through Moran’s I, a statistic that quantifies spatial autocorrelation.
Moran’s I for a variable is calculated as follows:
\[
I = \frac{n}{\sum_{i=1}^{n} \sum_{j=1}^{n} w_{ij}} \cdot
\frac{\sum_{i=1}^{n} \sum_{j=1}^{n} w_{ij} (X_i - \bar{X})(X_j -
\bar{X})}{\sum_{i=1}^{n} (X_i - \bar{X})^2}
\] where \(n\) is the number of
observations, \(X_i\) and \(X_j\) are the values of the variable at
locations \(i\) and \(j\), respectively, \(\bar{X}\) is the mean of the variable, and
\(w_{ij}\) is the spatial weight
between locations \(i\) and \(j\).
Here, we use a spatial weight matrix constructed using a “Queen”
contiguity method, which defines each unit’s neighbors based on shared
boundaries or vertices. This matrix remains consistent across the
analysis, although statisticians may use different weight matrices to
assess model sensitivity to neighbor definitions.
Testing the significance of spatial autocorrelation involves
evaluating whether the observed Moran’s I differs from what would be
expected under spatial randomness. In hypothesis testing, the null
hypothesis (\(H_0\)) is that there is
no spatial autocorrelation, while the alternative (\(H_a\)) posits the presence of spatial
autocorrelation. Using random permutations of data values across
locations, we generate a reference distribution of Moran’s I under the
null hypothesis and compare the observed statistic to this
distribution.
Beyond global spatial autocorrelation measured by Moran’s I, local
spatial autocorrelation identifies specific areas with clustering or
dispersion. The significance of local Moran’s I is tested similarly
using random permutations, and results can highlight statistically
significant clusters or outliers that global measures might miss.
Ordinary Least Squares Regression
Ordinary Least Squares (OLS) regression is a statistical technique
for estimating the relationship between a dependent variable and one or
more independent variables by minimizing the squared differences between
observed and predicted values. Key assumptions of OLS include linearity,
independence of observations, homoscedasticity (constant error
variance), normality of errors, and no multicollinearity among
predictors.
In our first assignment, we used OLS regression to assess how vacancy
rates, single-family housing percentage, educational attainment, and
poverty levels influence median house value. All predictors were
statistically significant, with vacancy rates and poverty levels
negatively affecting house values, while single-family housing and
educational attainment had positive effects. The model’s \(R^2\) was 0.66, explaining 66% of the
variance in house values. However, some predictors exhibited non-linear
patterns, and spatial autocorrelation suggested dependence among
observations, indicating that future models could benefit from spatial
regression techniques.
When data has a spatial component, the assumption that errors are
random and independent often doesn’t hold, as nearby observations may
exhibit similar error patterns. To test this, we can examine the spatial
autocorrelation of the residuals using Moran’s I, which quantifies the
degree of clustering in residuals. Another approach is to regress the
residuals on nearby residuals from neighboring areas, such as block
groups defined by the Queen matrix, to identify any spatial dependence.
These tests help determine if spatial autocorrelation is present,
indicating a need for spatial regression techniques.
In R, there are methods to test other key regression assumptions. For
homoscedasticity (constant error variance), which is related to the
independence of errors, we use the Breusch-Pagan Test,
the Koenker-Bassett Test, and the White
Test. The null hypothesis (\(H_0\)) is that errors are homoscedastic,
while the alternative hypothesis (\(H_a\)) is that errors exhibit
heteroscedasticity. For normality of errors, we can use the
Jarque-Bera test. The null hypothesis is that residuals
are normal, and the alternative hypothesis is that they are not normal.
We want to not be able to reject the null hypothesis (i.e., get a
p-value of 0.05 or higher).
Spatial Lag and Spatial Error Regression
In this report, we use R to run spatial lag and spatial error
regressions. Among the two methods, spatial lag regression assumes the
value of the dependent variable at one location is associated with the
values of that variable in nearby locations, where nearby is as defined
by the weights matrix W (rook, queen, within a certain distance of one
another). In short, it introduces a spatially lagged dependent variable
into the model, compared to our previous OLS regression. In our context,
the spatial lag model could be represented as the following:
\[
\text{LNMEDHVAL} = \rho W \cdot \text{LNMEDHVAL} + \beta_0 + \beta_1
\cdot \text{PCTVACANT} + \beta_2 \cdot \text{PCTSINGLES} + \beta_3 \cdot
\text{PCTBACHMOR} + \beta_4 \cdot \text{LNNBELPOV100} + \epsilon_i
\]
where \(\text{LNMEDHVAL}\) is the
log of median home value in location, \(\rho\) is the spatial lag coefficient that
measures the influence of neighboring areas, \(W\) is the spatial weights matrix (in this
case, the queenlist spatial weights), and \(W
\cdot \text{LNMEDHVAL}\) is the spatially lagged dependent
variable. The other terms are the same as in the OLS regression, where
\(\text{PCTVACANT}\), \(\text{PCTSINGLES}\), \(\text{PCTBACHMOR}\), and \(\text{LNNBELPOV}\) are the predictors,
\(\beta_1, \beta_2, \beta_3, \beta_4\)
are the coefficients, \(\beta_0\) is
the intercept term, and \(\epsilon_i\)
is the error term.
The spatial error model, on the other hand, assumes that the error
term is spatially autocorrelated, meaning that the residual in one
location is associated with residuals at nearby locations, where nearby
is also deifined by the weight matrix. The spatial error model could be
represented as the following:
\[
\text{LNMEDHVAL} = \beta_0 + \beta_1 \cdot \text{PCTVACANT} + \beta_2
\cdot \text{PCTSINGLES} + \beta_3 \cdot \text{PCTBACHMOR} + \beta_4
\cdot \text{LNNBELPOV100} + \lambda W \cdot \epsilon + u
\]
where \(\text{LNMEDHVAL}\) is the
log of median home value, \(\beta_0\)
is the intercept term, \(\text{PCTVACANT}\), \(\text{PCTSINGLES}\), \(\text{PCTBACHMOR}\), and \(\text{LNNBELPOV}\) are the predictors,
\(\beta_1, \beta_2, \beta_3, \beta_4\)
are the coefficients, as in OLS regression. \(\lambda\) is the spatial error coefficient
that measures the degree of spatial correlation in the error term, \(W\) is the spatial weights matrix, \(W \cdot \epsilon\) is the spatially lagged
error term, and \(u\) is the random
noise. To put it simply, we are regressing residuals on the nearest
neighbor residuals, thereby filtering the spatial information out of the
OLS residuals
Spatial error regression and spatial lag regression both require the
standard assumptions for OLS regression—such as linearity,
homoscedasticity, and normality of errors—except for the assumption of
spatial independence among observations. This adjustment allows the
model to account for spatial structure in either the dependent variable
(spatial lag) or the error term (spatial error). That said, their goal
is to account for spatial dependence in the data, aiming to reduce
spatial autocorrelation in the regression residuals. Both methods
minimize spatial patterns in residuals that could otherwise lead to
biased or inefficient estimates.
We compare the results of spatial lag and spatial error regression
with OLS to decide whether the spatial models perform better than OLS
based on a number of criteria: Akaike Information Criterion, Schwarz
Criterion, Log Likelihood, and Likelihood Ratio Test. The Akaike
Information Criterion (AIC) and Schwarz Criterion (SC
or BIC) are used to compare the goodness of fit of different
models. They are relative measures of the information that is lost when
a given model is used to describe reality and can be said to describe
the tradeoff between precision and complexity of the model. The lower
the AIC or SC, the better the model.
The Log-Likelihood is associated with the maximum
likelihood method of fitting a statistical model to the data and
estimating model parameters. Maximum likelihood picks the values of the
model parameters that make the data “more likely” than any other values
of the parameters would make them. Higher log-likelihood values indicate
a model that better explains the observed data.
The Likelihood Ratio Test is used to formally test
whether adding spatial dependence to a model (as in spatial lag or
spatial error models) significantly improves model fit compared to OLS.
For this test, the null hypothesis (\(H_0\)) state that the spatial model does
not provide a significantly better fit than OLS, while the alternative
hypothesis (\(H_a\)) states that the
spatial model provides a significantly better fit than OLS.
The decision rule is to reject the null hypothesis if the \(LR\) test statistic is significant (i.e.,
the p-value is below a chosen significance level, typically 0.05), and
conclude that the spatial model is a better fit than OLS. If not, OLS
may be adequate. It should be noted that the log likelihood method
and the likelihood ratio test should be used for comparing nested
models. Spatial lag and spatial error are not a special case of each
other – we cannot use the log likelihood ratio to compare them.
Alternatively, we can also compare the spatial models to OLS using
the Moran’s I statistic, which measures the spatial
autocorrelation of the residuals. Moran’s I ranges from -1 to 1, where
-1 indicates perfect dispersion, 0 indicates no spatial autocorrelation,
and 1 indicates perfect correlation. For our models, the goal is to
minimize spatial autocorrelation in the residuals. If the Moran’s I
statistic for the residuals of a spatial lag or spatial error model is
closer to zero than the Moran’s I for the OLS model, we can conclude
that the spatial model better captures spatial dependencies.
Geographically Weighted Regression
We will conduct our Geographically Weighted Regression (GWR) analyses
in R. GWR is a form of local regression that helps address spatial
heterogeneity in data, which is essential when analyzing spatial data
prone to Simpson’s Paradox — where a trend observed in aggregate data
can differ from trends in subsets. GWR allows us to examine
relationships at a local level rather than assuming they are uniform
across the study area. The general GWR equation can be expressed as:
\[
y_i = \beta_{i0} + \sum_{k=1}^{m} \beta_{ik}x_{ik} + \epsilon_i
\]
where: \(y_i\) is the dependent
variable at location \(i\), \(\beta_{i0}\) is the intercept for location
\(i\), allowing a unique baseline for
each location, \(\beta_{ik}\) is the
coefficient for the \(k\)-th predictor
at location \(i\), \(x_{ik}\) is the value of the \(k\)-th predictor variable at location \(i\), and \(\epsilon_i\) is the error term at location
\(i\).
In GWR, local regression is performed by fitting a regression model
at each observation point, using a subset of neighboring points, with
weights assigned based on their distance from the focal point. The
concept of bandwidth controls the number of neighbors included,
influencing how “local” each regression is. There are two types of
bandwidths: adaptive and fixed. A fixed bandwidth uses a constant
distance for all points, while an adaptive bandwidth varies, adjusting
to include a set number of nearby observations regardless of spatial
density. Here, we will use adaptive bandwidth, which is more appropriate
as it accounts for varying spatial densities, providing a flexible
analysis that better captures local relationships in areas with
different population distributions.
Although GWR allows for spatial variation in relationships, the
standard OLS assumptions (linearity, independence, homoscedasticity, and
normality) still apply. Multicollinearity is assessed using the
Condition Number, and high multicollinearity can cause issues in GWR,
leading to unstable estimates and clustering in parameter estimates. It
is also important to note that GWR does not provide p-values for
coefficients, as the model focuses on exploring spatial patterns rather
than testing global hypotheses.
Results
Global and Local Moran’s I
The Global Moran’s I analysis for the dependent variable, \(\text{LNMEDHVAL}\) (the natural log of
median house value), reveals a pronounced level of spatial
autocorrelation. With a Moran’s I statistic of 0.8, the results indicate
a strong positive spatial autocorrelation. This high value suggests that
areas with similar median house values tend to cluster geographically
within the study area. In other words, neighborhoods with either high or
low house values are more likely to be located near other neighborhoods
with similar values, rather than being randomly distributed across
space. This spatial clustering points to the presence of spatial
dependencies in housing values, possibly driven by neighborhood
characteristics, socio-economic factors, or other spatial processes
influencing property values across the region.
To validate the significance of this observed spatial
autocorrelation, a Monte Carlo permutation test was conducted using 1000
simulations. This approach involved randomly permuting the values of
\(\text{LNMEDHVAL}\) across spatial
units to generate a distribution of Moran’s I values under the null
hypothesis of no spatial autocorrelation. The results, visualized in a
histogram of permuted Moran’s I values, show that the observed Moran’s I
of 0.8 lies at the extreme end of this distribution, marked in red. With
an observed rank of 1000 (the highest rank in the distribution), the
observed Moran’s I value exceeded all permuted values, emphasizing the
extremity of the spatial clustering in the actual data.
The test result is further supported by a highly significant p-value
(\(p < 2 \times 10^{-16}\)). This
exceptionally low p-value strongly rejects the null hypothesis of no
spatial autocorrelation, confirming that the spatial arrangement of
\(\text{LNMEDHVAL}\) values is not
random. Instead, the observed clustering is statistically significant,
indicating that spatial processes are likely influencing the
distribution of housing values in the study area.
globalmoranMC<-moran.mc(regData$LNMEDHVAL, queenlist, nsim=999, alternative="two.sided")
globalmoranMC
##
## Monte-Carlo simulation of Moran I
##
## data: regData$LNMEDHVAL
## weights: queenlist
## number of simulations + 1: 1000
##
## statistic = 0.8, observed rank = 1000, p-value <0.0000000000000002
## alternative hypothesis: two.sided
This graph shows the results of the Monte Carlo permutation test to
assess the significance of the observed Moran’s I statistic.The
histogram shows the frequency of Moran’s I values generated by these
random permutations, with the observed Moran’s I value highlighted in
red. The observed statistic of 0.8 stands far to the right of the
permuted values, underscoring its extremity and significance. The high
observed rank (1000) indicates that none of the permuted values exceeded
the actual Moran’s I. This extremely low p-value provides strong
evidence against the null hypothesis of no spatial autocorrelation,
confirming that the spatial clustering observed in \(\text{LNMEDHVAL}\) is statistically
significant and unlikely to be due to random variation.
ggplot(data.frame(res = globalmoranMC$res), aes(x = res)) +
geom_histogram(bins = 100, fill = "#283d3b") +
geom_vline(xintercept = globalmoranMC$statistic, color = "#c44536", linetype = 'dashed', size = 1) +
labs(title = "Observed and Permuted Global Moran's I",
subtitle = "Observed Moran's I in Red",
x = "Moran's I",
y = "Count") +
theme_light() +
theme(plot.subtitle = element_text(size = 9,face = "italic"),
plot.title = element_text(size = 12, face = "bold"),
axis.text.x=element_text(size=6),
axis.text.y=element_text(size=6),
axis.title=element_text(size=8))

This graph offers a different perspective on the spatial structure of
\(\text{LNMEDHVAL}\) by displaying a
scatter plot of the variable’s values against their spatial lag (a
measure of neighboring values). The x-axis represents the logged median
house values \(\text{LNMEDHVAL}\),
while the y-axis displays the spatially lagged values of \(\text{LNMEDHVAL}\), computed based on a
queen contiguity spatial weights matrix that considers neighboring
spatial units. The positive slope of the red trend line in the scatter
plot indicates a positive spatial autocorrelation, where areas with
higher median house values are typically surrounded by other areas with
high values, and similarly, areas with lower values are near other
low-value areas. This linear relationship between a location’s \(\text{LNMEDHVAL}\) and the average values
in surrounding locations highlights the clustering of similar values and
supports the result from the Global Moran’s I statistic.
ggplot(data = data.frame(
LNMEDHVAL = regData$LNMEDHVAL,
spatial_lag = lag.listw(queenlist, regData$LNMEDHVAL)
), aes(x = LNMEDHVAL, y = spatial_lag)) +
geom_point(color = "#283d3b", alpha = 0.7, size = 0.6) +
geom_smooth(method = "lm", color = "#c44536", se = FALSE) +
labs(title = "Global Moran's I Scatter Plot",
x = "Logged Median House Value",
y = "Spatial Lag of LNMEDHVAL") +
theme_light() +
theme(plot.subtitle = element_text(size = 9,face = "italic"),
plot.title = element_text(size = 12, face = "bold"),
axis.text.x=element_text(size=6),
axis.text.y=element_text(size=6),
axis.title=element_text(size=8))

In a Local Moran’s I significance map, areas with significant low
p-values refers to area where the spatial autocorrelation is
statistically significant, either hotspots of concentrated high values
or cold spots of low values. There areas are mostly found in the
northwestern and central parts of the city. As we may see, these areas
are then surrounded by areas with slightly higher p-values and then
areas with even higher p-values, until p becomes insignificant.
moranSig.plot <- function(df, listw, title) {
local <- localmoran(x = df$LNMEDHVAL, listw = listw, zero.policy = FALSE)
df$Pr.z <- local[, "Pr(z != E(Ii))"]
df$pval_category <- cut(df$Pr.z,
breaks = c(0, 0.001, 0.01, 0.05, 1),
labels = c("0.000 - 0.001", "0.001 - 0.010", "0.010 - 0.050", "0.050 - 1.000"),
include.lowest = TRUE)
if (!inherits(df, "sf")) {
df <- st_as_sf(df)
}
ggplot(data = df) +
geom_sf(aes(fill = pval_category), color = NA, alpha = 0.9) +
scale_fill_brewer(type = "div", palette = 6, name = "P-Value") +
labs(title = title) +
theme(legend.text = element_text(size = 9),
legend.title = element_text(size = 10),
axis.text.x = element_blank(),
axis.ticks.x = element_blank(),
axis.text.y = element_blank(),
axis.ticks.y = element_blank(),
plot.subtitle = element_text(size = 9, face = "italic"),
plot.title = element_text(size = 12, face = "bold"),
panel.background = element_blank(),
panel.border = element_rect(colour = "grey", fill = NA, size = 0.8))
}
moranSig.plot(localmoran, queenlist, 'Significance Map of Local Moran I')

The Cluster Map derived from the Local Moran’s I analysis classified
census tracts in Philadelphia into high-high, high-low, low-high,
low-low, or not significant, representing different types of spatial
relationships in house values within neighborhoods and their
surroundings.
High-High Clusters: Areas classified as high-high
are those where high values of median house prices are surrounded by
other high-value areas. These clusters are prominently located in the
northwestern parts of the city and some central regions, indicating
pockets of economic affluence. The high concentration of high-value
properties in these regions suggests established, affluent neighborhoods
where housing prices remain high due to demand and possibly the presence
of amenities or other attractive urban features.
Low-Low Clusters: Low-low clusters represent areas
where low property values are surrounded by other low-value areas,
highlighting economically disadvantaged zones. These clusters are
predominantly found in the southwestern and northeastern parts of the
city. The spatial clustering of low-value properties in these areas
suggests neighborhoods that may face economic challenges, possibly with
limited access to amenities or fewer investment opportunities. These
regions may require targeted policy interventions to address underlying
issues that contribute to the lower property values.
High-Low Clusters: High-low clusters are
transitional zones where high-value areas are adjacent to lower-value
areas. These areas, marked in light red on the map, are generally
scattered around the boundaries of high-value neighborhoods, such as in
sections of central and northwest Philadelphia. The proximity of
high-value properties to lower-value ones in these clusters can indicate
economic contrasts or areas experiencing gentrification, where property
values in traditionally lower-income neighborhoods may be increasing due
to spillover effects from nearby affluent areas.
Low-High Clusters: Low-high clusters, where
low-value properties are surrounded by higher-value areas, are less
common but appear in the northern and eastern parts of the city. These
clusters suggest isolated pockets of economic disadvantage within more
affluent areas. This pattern may indicate areas that are yet to benefit
from surrounding economic growth or might be experiencing challenges
that prevent them from aligning with the prosperity of neighboring
regions.
Not Significant Areas: Lastly, the not significant
areas, shaded in gray, indicate neighborhoods where the local Moran’s I
statistic was not significant. These regions are scattered throughout
the city, representing areas where house values do not exhibit strong
spatial clustering. The lack of significant clustering in these areas
suggests a more random distribution of house values, which may occur in
more mixed-use or transitional neighborhoods where economic
characteristics are varied.
hl.plot <- function(df, listw) {
local <- localmoran(x = df$LNMEDHVAL, listw = listw, zero.policy = FALSE)
quadrant <- vector(mode = 'numeric', length = nrow(df))
m.prop <- df$LNMEDHVAL - mean(df$LNMEDHVAL)
m.local <- local[, 1] - mean(local[, 1])
signif <- 0.05
quadrant[m.prop > 0 & m.local > 0] <- 1 # high-high
quadrant[m.prop < 0 & m.local < 0] <- 2 # low-low
quadrant[m.prop < 0 & m.local > 0] <- 4 # low-high
quadrant[m.prop > 0 & m.local < 0] <- 3 # high-low
quadrant[local[, 5] > signif] <- 5 # insignificant
df$quadrant <- factor(quadrant, levels = c(1, 3, 5, 2, 4),
labels = c("High-High", "High-Low", "Non-Significant", "Low-Low", "Low-High"))
if (!inherits(df, "sf")) {
df <- st_as_sf(df)
}
ggplot(data = df) +
geom_sf(aes(fill = quadrant), color = "#848884", lwd = 0.07) +
scale_fill_brewer(type = "div", palette = 6, name = "Cluster Type") +
labs(title = "Local Moran's I Cluster Map") +
theme(legend.position="right",
axis.text.x=element_blank(),
axis.text.y=element_blank(),
axis.ticks =element_blank(),
axis.title.x = element_blank(),
axis.title.y = element_blank(),
plot.subtitle = element_text(size = 9,face = "italic"),
plot.title = element_text(size = 12, face = "bold"),
panel.background = element_blank(),
panel.border = element_rect(colour = "grey", fill=NA, linewidth=0.8)
)
}
hl.plot(regData, queenlist)

OLS Regression Results
Below, we will provide a quick walk through of the OLS regression
results. Detail interpretation and dicussion of the results can be found
in the GitHub
repository for assignment 1.
All predictors in our OLS regression, which include \(\text{PCTSINGLES}\), \(\text{PCTVACANT}\), \(\text{LNNBELPOV}\), and \(\text{PCTBACHMOR}\), are statistically
significant in explaining \(\text{LNMEDHVAL}\). The model accounts for
approximately 66.2% of the variance, as indicated by the R-squared value
of 0.662.
OLS <- lm(LNMEDHVAL ~ PCTVACANT + PCTSINGLES + PCTBACHMOR + LNNBELPOV, data=regData)
fitted_values <- fitted(OLS)
residuals_values <- residuals(OLS)
standardized_residuals <- rstandard(OLS)
resnb<-sapply(queen, function(x) mean(standardized_residuals[x]))
regData <- regData %>%
mutate(
Fitted = fitted_values,
Residuals = residuals_values,
Standardized_Residuals = standardized_residuals,
Residuals_NB = resnb)
summary(OLS)
##
## Call:
## lm(formula = LNMEDHVAL ~ PCTVACANT + PCTSINGLES + PCTBACHMOR +
## LNNBELPOV, data = regData)
##
## Residuals:
## Min 1Q Median 3Q Max
## -2.2582 -0.2039 0.0382 0.2174 2.2434
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 11.113778 0.046532 238.84 < 0.0000000000000002 ***
## PCTVACANT -0.019156 0.000978 -19.59 < 0.0000000000000002 ***
## PCTSINGLES 0.002977 0.000703 4.23 0.000024 ***
## PCTBACHMOR 0.020910 0.000543 38.49 < 0.0000000000000002 ***
## LNNBELPOV -0.078903 0.008457 -9.33 < 0.0000000000000002 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.366 on 1715 degrees of freedom
## Multiple R-squared: 0.662, Adjusted R-squared: 0.662
## F-statistic: 841 on 4 and 1715 DF, p-value: <0.0000000000000002
The results from the Breusch-Pagan, Koenker-Bassett, and White’s
tests all detect heteroscedasticity in the model, as all p-values are
extremely low. This confirms a clear violation of the homoscedasticity
assumption in OLS regression.
# Breusch-Pagan Test
bptest(OLS, studentize=FALSE)
##
## Breusch-Pagan test
##
## data: OLS
## BP = 113, df = 4, p-value <0.0000000000000002
# Koenker-Bassett Test
bptest(OLS)
##
## studentized Breusch-Pagan test
##
## data: OLS
## BP = 43, df = 4, p-value = 0.00000001
# White Test
white_test(OLS)
## White's test results
##
## Null hypothesis: Homoskedasticity of the residuals
## Alternative hypothesis: Heteroskedasticity of the residuals
## Test Statistic: 43.94
## P-value: 0
Comparing to the scatter plot we made to identify heteroscedasticity
from the previous assignment, the residuals in this scatter plot show no
discernible trend of rising or falling variance with increasing fitted
values; instead, they seem to be pretty uniformly distributed around the
horizontal line at zero. Regardless, the Breusch-Pagan test is often
more sensitive than a residual plot. Even small deviations that are hard
to see visually may be detected.
ggplot(regData, aes(x = Fitted, y = Standardized_Residuals)) +
geom_point(color = "#283d3b", alpha = 0.9, size = 0.6) +
geom_hline(yintercept = 0, linetype = "dashed", color = "#c44536", size = 1) + #
labs(
title = "Scatter Plot of Standardized Residuals vs Fitted Values",
x = "Fitted Values",
y = "Standardized Residuals"
) +
theme_light() +
theme(plot.subtitle = element_text(size = 9,face = "italic"),
plot.title = element_text(size = 12, face = "bold"),
axis.text.x=element_text(size=6),
axis.text.y=element_text(size=6),
axis.title=element_text(size=8))

The results of the Jarque-Bera test indicate a significant deviation
from normality in the residuals. The p-value is well below typical
significance levels, and rejects the null hypothesis that the residuals
are normally distributed. Therefore, the test results suggest that the
residuals do not meet the normality assumption required for OLS
regression.
# Jarque-Bera Test
jarque.bera.test(OLS$residuals)
##
## Jarque Bera Test
##
## data: OLS$residuals
## X-squared = 779, df = 2, p-value <0.0000000000000002
Comparing to the histogram of standardized residuals from the
previous assignment, we may also notice that the residuals are not
perfectly normal. The histogram reveals a slight departure from a normal
distribution and is left skewed. Despite that the skewness is not very
pronounced, it is still consistent with the Jarque-Bera test
results.
ggplot(regData, aes(x = Standardized_Residuals)) +
geom_histogram(bins = 30, fill = "#283d3b", alpha = 0.9) +
labs(title = "Histogram of Standardized Residuals",
x = "Standardized Residuals",
y = "Frequency") +
theme_light() +
theme(plot.subtitle = element_text(size = 9,face = "italic"),
plot.title = element_text(size = 12, face = "bold"),
axis.text.x=element_text(size=6),
axis.text.y=element_text(size=6),
axis.title=element_text(size=8))

The scatterplot below shows the relationship between the standardized
residuals of the OLS model and the residuals of their nearest neighbors.
The upward-sloping trend line indicates a positive relationship between
these residuals and their neighbors, suggesting spatial autocorrelation.
The coefficient for the residuals of their nearest neighbors is 0.7323,
with a highly significant p-value, demonstrating a strong positive
relationship. This implies that residuals are positively correlated with
those of their closest neighbors, implying spatial dependence.
ggplot(regData, aes(x = Residuals_NB, y = Standardized_Residuals)) +
geom_point(color = "#283d3b", alpha = 0.9, size = 0.6) +
geom_smooth(method = "lm", se = FALSE, color = "#c44536", size = 1) +
labs(title = "Residuals vs. Nearest Neighbor Residuals",
x = "Nearest Neighbor Residuals",
y = "Standardized Residuals") +
theme_light() +
theme(plot.subtitle = element_text(size = 9,face = "italic"),
plot.title = element_text(size = 12, face = "bold"),
axis.text.x=element_text(size=6),
axis.text.y=element_text(size=6),
axis.title=element_text(size=8))

The Moran’s I scatterplot and the results from the permutations for
OLS regression residuals both indicate significant spatial
autocorrelation. The scatterplot shows a positive relationship between
the logged median house values and their spatially lagged values, with a
positive slope, confirming that high values tend to be near other high
values, and low values cluster with other low values. The Moran’s I
statistic from the Monte Carlo simulation is approximately 0.3, with an
extremely low p-value, confirming that this spatial autocorrelation is
statistically significant.
This significant spatial autocorrelation in the OLS residuals is
problematic because it violates the OLS assumption of independent
residuals. When residuals are spatially autocorrelated, it suggests that
the model is missing spatial structure in the data, which could lead to
biased or inefficient estimates.
OLS_moranMC<-moran.mc(standardized_residuals, queenlist, nsim=999, alternative="two.sided")
OLS_moranMC
##
## Monte-Carlo simulation of Moran I
##
## data: standardized_residuals
## weights: queenlist
## number of simulations + 1: 1000
##
## statistic = 0.3, observed rank = 1000, p-value <0.0000000000000002
## alternative hypothesis: two.sided
Both the Moran’s I statistic and the positive beta coefficient from
the regression of standardized residuals on their nearest neighbors tell
a similar story. They both reveal that spatial dependence is present in
the residuals, suggesting that a spatial model, such as Geographically
Weighted Regression (GWR) or a spatial autoregressive model, would be
more appropriate for capturing the underlying spatial relationships in
the data.
plt1 <- ggplot(data.frame(res = OLS_moranMC$res), aes(x = res)) +
geom_histogram(bins = 100, fill = "#283d3b") +
geom_vline(xintercept =OLS_moranMC$statistic, color = "#c44536", linetype = 'dashed', size = 1) +
labs(title = "Observed and Permuted Moran's I of OLS Residuals",
subtitle = "Observed Moran's I in Red",
x = "Moran's I",
y = "Count") +
theme_light() +
theme(plot.subtitle = element_text(size = 9,face = "italic"),
plot.title = element_text(size = 12, face = "bold"),
axis.text.x=element_text(size=6),
axis.text.y=element_text(size=6),
axis.title=element_text(size=8))
plt2 <- ggplot(data = data.frame(
residuals =standardized_residuals,
spatial_lag = lag.listw(queenlist, standardized_residuals)
), aes(x = residuals, y = spatial_lag)) +
geom_point(color = "#283d3b", alpha = 0.9, size = 0.6) +
geom_smooth(method = "lm", color = "#c44536", se = FALSE) +
labs(title = "Moran's I Scatter Plot for OLS Residuals",
x = "Logged Median House Value",
y = "Spatial Lag of LNMEDHVAL") +
theme_light() +
theme(plot.subtitle = element_text(size = 9,face = "italic"),
plot.title = element_text(size = 12, face = "bold"),
axis.text.x=element_text(size=6),
axis.text.y=element_text(size=6),
axis.title=element_text(size=8))
plt1 + plt2

Spatial Lag and Error Regression Results
Spatial Lag Regression
In the spatial lag regression output, we may see that the term \(\text{LNMEDHVAL}\), represented by \(\rho\) in the model, has an estimate of
0.651 and an extremely significant p-value (\(p < 2.22 \times 10^{-16}\)).This
indicates that nearby values of the dependent value influence each
other. The significant positive coefficient (\(\rho = 0.651\)) suggests a substantial
positive spatial lag effect, meaning that higher median home values in
neighboring areas are associated with higher median home values in the
area being examined.
All predictors in the spatial lag model are significant. \(\text{PCTVACANT}\) has a coefficient of
-0.0085 and is highly significant since \(p
< 2.22 \times 10^{-16}\). It means a higher vacancy rate is
associated with lower median home values. \(\text{PCTSINGLES}\) has a coefficient of
0.0020, significant with a \(p <
0.0001\). The positive association suggests that areas with a
higher proportion of single households may slightly increase median home
values. \(\text{PCTBACHMOR}\) has a
coefficient of 0.0085 and is extremely significant (\(p < 2.22 \times 10^{-16}\)). Higher
education levels are positively associated with home values, meaning
that more educated areas tend to have higher home values. \(\text{LNNBELPOV}\) has a coefficient of
-0.0341, also highly significant (\(p < 1
\times 10^{-7}\)). The negative association suggests that higher
poverty levels are associated with lower median home values.
The OLS model also shows significant coefficients for all predictors,
but with larger effect sizes. For example, has a coefficient of -0.0192
in OLS, compared to -0.0085 in spatial lag. This suggests that OLS
overestimates the influence of these predictors due to omitted spatial
dependence. For the other predictors, the OLS coefficients are also
larger in magnitude than the spatial lag coefficients.
SL <- lagsarlm(LNMEDHVAL ~ PCTVACANT + PCTSINGLES + PCTBACHMOR + LNNBELPOV, data=regData, queenlist)
summary(SL)
##
## Call:lagsarlm(formula = LNMEDHVAL ~ PCTVACANT + PCTSINGLES + PCTBACHMOR +
## LNNBELPOV, data = regData, listw = queenlist)
##
## Residuals:
## Min 1Q Median 3Q Max
## -1.655421 -0.117248 0.018654 0.133126 1.726436
##
## Type: lag
## Coefficients: (asymptotic standard errors)
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) 3.89845489 0.20111357 19.3843 < 0.00000000000000022
## PCTVACANT -0.00852940 0.00074367 -11.4694 < 0.00000000000000022
## PCTSINGLES 0.00203342 0.00051577 3.9425 0.00008063503
## PCTBACHMOR 0.00851381 0.00052193 16.3120 < 0.00000000000000022
## LNNBELPOV -0.03405466 0.00629287 -5.4116 0.00000006246
##
## Rho: 0.651, LR test value: 912, p-value: < 0.000000000000000222
## Asymptotic standard error: 0.018
## z-value: 36.1, p-value: < 0.000000000000000222
## Wald statistic: 1301, p-value: < 0.000000000000000222
##
## Log likelihood: -256 for lag model
## ML residual variance (sigma squared): 0.0719, (sigma: 0.268)
## Number of observations: 1720
## Number of parameters estimated: 7
## AIC: 525, (AIC for lm: 1435)
## LM test for residual autocorrelation
## test value: 67.7, p-value: 0.00000000000000022204
We ran Breusch-Pagan test to assess whether the residuals of the
spatial lag regression model exhibit heteroscedasticity. As we may see,
the test statistic for the spatial lag regression is \(BP = 211\) with \(df = 4\), and \(p
< 2 \times 10^{-16}\). Given the extremely low p-value, we
reject the null hypothesis of homoscedasticity, indicating that
residuals in the spatial lag regression model remain
heteroscedastic.
# Breusch-Pagan Test
bptest.Sarlm(SL, studentize=FALSE)
##
## Breusch-Pagan test
##
## data:
## BP = 211, df = 4, p-value <0.0000000000000002
When comparing the OLS and spatial lag regression models, several
metrics show the spatial lag model provides a better fit. The spatial
lag model has a significantly lower AIC (525) than OLS (1435),
indicating a better model fit by penalizing less for added complexity.
Similarly, the Schwarz Criterion is much lower for the spatial lag
model, suggesting it captures the structure of the data more effectively
than the OLS model. The spatial lag model (-256) has a higher log
likelihood than OLS (-711), meaning that it better explains the
variability in the data.
# Akaike Information Criterion
aic_ols <- AIC(OLS)
aic_sl <- AIC(SL)
# Schwarz Criterion
bic_ols <- BIC(OLS)
bic_sl <- BIC(SL)
# The Log Likelihood
loglik_ols <- logLik(OLS)
loglik_sl <- logLik(SL)
results <- data.frame(
Model = c("OLS Regression", "Spatial Lag Regression"),
AIC = c(aic_ols, aic_sl),
SchwarzCriterion = c(bic_ols, bic_sl),
LogLikelihood = c(loglik_ols, loglik_sl)
)
results %>%
kable(row.names = FALSE) %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed"))
|
Model
|
AIC
|
SchwarzCriterion
|
LogLikelihood
|
|
OLS Regression
|
1435
|
1468
|
-711
|
|
Spatial Lag Regression
|
525
|
564
|
-256
|
The Likelihood Ratio Test assesses the improvement in model fit
between the OLS and spatial lag models, and the result we get here shows
\(LR = 912\) with \(df = 1\), and \(p
< 2 \times 10^{-16}\). With a large test statistic and low
p-value, we conclude that the spatial lag model significantly improves
fit over the OLS model.
# The Likelihood Ratio Test
lr_test <- LR.Sarlm(SL, OLS)
lr_test
##
## Likelihood ratio for spatial linear models
##
## data:
## Likelihood ratio = 912, df = 1, p-value <0.0000000000000002
## sample estimates:
## Log likelihood of SL Log likelihood of OLS
## -256 -711
Finally, we examined Moran’s I for the spatial lag regression model’s
residuals.The observed Moran’s I of -0.08 suggests a small negative
spatial autocorrelation in the residuals of the spatial lag model. With
\(p = 0.002\), we reject the null
hypothesis of no spatial autocorrelation. This negative Moran’s I
indicates that residuals are distributed with slight spatial dispersion
rather than clustering, suggesting the spatial lag model effectively
accounts for most spatial dependencies in the data.
SL_moranMc<-moran.mc(SL$residuals, queenlist,999, alternative="two.sided")
SL_moranMc
##
## Monte-Carlo simulation of Moran I
##
## data: SL$residuals
## weights: queenlist
## number of simulations + 1: 1000
##
## statistic = -0.08, observed rank = 1, p-value = 0.002
## alternative hypothesis: two.sided
Both the residual histograms as well as the scatter plot support this
conclusion. The histogram of residuals is also approximately normally
distributed, and the scatter plot of residuals against fitted values
shows no clear pattern or trend. All of these suggest that the spatial
lag model is a good fit for the data compared to OLS.
plt3 <- ggplot(data.frame(res = SL$residuals), aes(x = res)) +
geom_histogram(bins = 100, fill = "#283d3b") +
geom_vline(xintercept =SL_moranMc$statistic, color = "#c44536", linetype = 'dashed', size = 1) +
labs(title = "Observed and Permuted Moran's I of SL Residuals",
subtitle = "Observed Moran's I in Red",
x = "Moran's I",
y = "Count") +
theme_light() +
theme(plot.subtitle = element_text(size = 9,face = "italic"),
plot.title = element_text(size = 12, face = "bold"),
axis.text.x=element_text(size=6),
axis.text.y=element_text(size=6),
axis.title=element_text(size=8))
plt4 <- ggplot(data = data.frame(
residuals =SL$residuals,
spatial_lag = lag.listw(queenlist, SL$residuals)
), aes(x = residuals, y = spatial_lag)) +
geom_point(color = "#283d3b", alpha = 0.9, size = 0.6) +
geom_smooth(method = "lm", color = "#c44536", se = FALSE) +
labs(title = "Moran's I Scatter Plot for SL Residuals",
x = "Logged Median House Value",
y = "Spatial Lag of LNMEDHVAL") +
theme_light() +
theme(plot.subtitle = element_text(size = 9,face = "italic"),
plot.title = element_text(size = 12, face = "bold"),
axis.text.x=element_text(size=6),
axis.text.y=element_text(size=6),
axis.title=element_text(size=8))
plt3 + plt4

Spatial Error Regression
In the spatial error regression model, the term \(\lambda\) represents the spatial
autocorrelation within the model’s error terms. In this case, \(\lambda\) is estimated at 0.815 and is
statistically significant, with \(p < 2.22
\times 10^{-16}\). This highly significant and large value of
\(\lambda\) suggests a strong spatial
dependency in the error terms.
Examining the individual predictors in the model, all variables are
statistically significant at a high confidence level. \(\text{PCTVACANT}\) has an estimate of
-0.0058 (\(p < 6.94 \times
10^{-9}\)), indicating that vacancy rates negatively affect
median home values. \(\text{PCTSINGLES}\) has a positive
coefficient of 0.0027 (\(p < 1.61 \times
10^{-5}\)), suggesting a small positive association with median
home values. \(\text{PCTBACHMOR}\) ,
representing the percentage of bachelor’s degrees or higher, shows a
positive effect with an estimate of 0.0098 (\(p < 2.20 \times 10^{-16}\)), indicating
that higher education levels correlate with higher home values. \(\text{LNNBELPOV}\) has a negative estimate
of -0.0345 and \(p < 1.11 \times
10^{-6}\), implying that higher levels of neighborhood poverty
are associated with lower median home values.
Similar to spatial lag regression, when comparing these results with
the OLS regression model, we observe that the coefficients for our
predictors are all smaller in magnitude than their OLS counterparts. For
instance, had a coefficient of -0.019156 in the OLS model, while in the
spatial error model, it is reduced to -0.0058. This reduction in
coefficient magnitude suggests that the spatial error model provides a
more conservative estimate of the effects of these predictors on median
home values, likely due to the accounted spatial autocorrelation.
SE <- errorsarlm(LNMEDHVAL ~ PCTVACANT + PCTSINGLES + PCTBACHMOR + LNNBELPOV, data=regData, queenlist)
summary(SE)
##
## Call:errorsarlm(formula = LNMEDHVAL ~ PCTVACANT + PCTSINGLES + PCTBACHMOR +
## LNNBELPOV, data = regData, listw = queenlist)
##
## Residuals:
## Min 1Q Median 3Q Max
## -1.926477 -0.115408 0.014889 0.133852 1.948664
##
## Type: error
## Coefficients: (asymptotic standard errors)
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) 10.90643427 0.05346777 203.9815 < 0.00000000000000022
## PCTVACANT -0.00578308 0.00088670 -6.5220 0.00000000006937
## PCTSINGLES 0.00267792 0.00062083 4.3134 0.00001607389089
## PCTBACHMOR 0.00981293 0.00072896 13.4615 < 0.00000000000000022
## LNNBELPOV -0.03453409 0.00708933 -4.8713 0.00000110881162
##
## Lambda: 0.815, LR test value: 678, p-value: < 0.000000000000000222
## Asymptotic standard error: 0.0164
## z-value: 49.8, p-value: < 0.000000000000000222
## Wald statistic: 2477, p-value: < 0.000000000000000222
##
## Log likelihood: -373 for error model
## ML residual variance (sigma squared): 0.0766, (sigma: 0.277)
## Number of observations: 1720
## Number of parameters estimated: 7
## AIC: 759, (AIC for lm: 1435)
Based on the results of the Breusch-Pagan test, the spatial lag
regression residuals are indeed heteroscedastic. The test statistic is
\(BP = 23\) with \(df = 4\), and \(p
< 0.0001\). Since the p-value is significantly lower than the
conventional alpha levels (0.01, 0.05), we reject the null hypothesis of
homoscedasticity. This indicates that the variance of the residuals is
not constant across observations, suggesting the presence of
heteroscedasticity in the model’s residuals.
# Breusch-Pagan Test
bptest.Sarlm(SE, studentize=FALSE)
##
## Breusch-Pagan test
##
## data:
## BP = 23, df = 4, p-value = 0.0001
We also compared the spatial error model to the OLS model using the
AIC, SC, log-likelihood, and likelihood ratio test. The spatial error
model has a lower AIC (759) and SC (798) than the OLS model (1435 and
1468, respectively), indicating a better fit. The log-likelihood of the
spatial error model (-373) is also higher than that of the OLS model
(-711), suggesting that the spatial error model better explains the
variability in the data.
# Akaike Information Criterion
aic_se <- AIC(SE)
# Schwarz Criterion
bic_se <- BIC(SE)
# The Log Likelihood
loglik_se <- logLik(SE)
results <- data.frame(
Model = c("OLS Regression", "Spatial Lag Regression", "Spatial Error Regression"),
AIC = c(aic_ols, aic_sl, aic_se),
SchwarzCriterion = c(bic_ols, bic_sl, bic_se),
LogLikelihood = c(loglik_ols, loglik_sl, loglik_se)
)
results %>%
kable(row.names = FALSE) %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed"))
|
Model
|
AIC
|
SchwarzCriterion
|
LogLikelihood
|
|
OLS Regression
|
1435
|
1468
|
-711
|
|
Spatial Lag Regression
|
525
|
564
|
-256
|
|
Spatial Error Regression
|
759
|
798
|
-373
|
According to the Likelihood Ratio Test, we see \(LR = 678\) with \(df = 1\), and \(p
< 2 \times 10^{-16}\). With a large test statistic and low
p-value, we may also conclude that the spatial error model significantly
improves fit over the OLS model.
lr_test <- LR.Sarlm(SE, OLS)
lr_test
##
## Likelihood ratio for spatial linear models
##
## data:
## Likelihood ratio = 678, df = 1, p-value <0.0000000000000002
## sample estimates:
## Log likelihood of SE Log likelihood of OLS
## -373 -711
Finally, we examined Moran’s I for the spatial error regression
model’s residuals. The observed Moran’s I of -0.09 suggests a small
negative spatial autocorrelation in the residuals of the spatial error
model. With \(p = 0.002\), we reject
the null hypothesis of no spatial autocorrelation. This negative Moran’s
I indicates that residuals are distributed with slight spatial
dispersion rather than clustering, suggesting the spatial error model
effectively accounts for most spatial dependencies in the data.
SE_moranMc<-moran.mc(residuals(SE), queenlist,999, alternative="two.sided")
SE_moranMc
##
## Monte-Carlo simulation of Moran I
##
## data: residuals(SE)
## weights: queenlist
## number of simulations + 1: 1000
##
## statistic = -0.09, observed rank = 1, p-value = 0.002
## alternative hypothesis: two.sided
Both the residual histograms as well as the scatter plot support this
conclusion here again. The histogram of residuals is approximately
normally distributed, and the scatter plot of residuals against fitted
values shows a much less evident trend compared to the OLS model.
Therefore, all of these suggest that the spatial error model is a good
fit for the data compared to OLS.
plt5 <- ggplot(data.frame(res = residuals(SE)), aes(x = res)) +
geom_histogram(bins = 100, fill = "#283d3b") +
geom_vline(xintercept =SE_moranMc$statistic, color = "#c44536", linetype = 'dashed', size = 1) +
labs(title = "Observed and Permuted Moran's I of SE Residuals",
subtitle = "Observed Moran's I in Red",
x = "Moran's I",
y = "Count") +
theme_light() +
theme(plot.subtitle = element_text(size = 9,face = "italic"),
plot.title = element_text(size = 12, face = "bold"),
axis.text.x=element_text(size=6),
axis.text.y=element_text(size=6),
axis.title=element_text(size=8))
plt6 <- ggplot(data = data.frame(
residuals = residuals(SE),
spatial_lag = lag.listw(queenlist, residuals(SE))
), aes(x = residuals, y = spatial_lag)) +
geom_point(color = "#283d3b", alpha = 0.9, size = 0.6) +
geom_smooth(method = "lm", color = "#c44536", se = FALSE) +
labs(title = "Moran's I Scatter Plot for SE Residuals",
x = "Logged Median House Value",
y = "Spatial Lag of LNMEDHVAL") +
theme_light() +
theme(plot.subtitle = element_text(size = 9,face = "italic"),
plot.title = element_text(size = 12, face = "bold"),
axis.text.x=element_text(size=6),
axis.text.y=element_text(size=6),
axis.title=element_text(size=8))
plt5 + plt6

It should be noted that here, we also compared spatial lag model with
the spatial error model. The spatial lag model has a lower AIC (525) and
SC (564) than the spatial error model (759 and 798, respectively),
indicating a better fit. The log-likelihood of the spatial lag model
(-256) is also less negative than that of the spatial lag error (-373),
suggesting that the spatial lag model better explains the variability in
the data.
Geographically Weighted Regression Results
The \(R^2\) for the OLS regression
model is 0.662, while the \(R^2\)
(Quasi-global \(R^2\) ) for the GWR
model is 0.848. The higher \(R^2\)
value of the GWR model indicates that it does a better job of explaining
the variance in the dependent variable \(\text{LNMEDHVAL}\) compared to the OLS
model. This improvement suggests that the spatial variability captured
by the GWR model provides a more accurate representation of the
relationships between the predictors and the dependent variable, as GWR
can account for spatial heterogeneity that OLS cannot.
Based on the Akaike Information Criterion (AIC) values, the GWR
model, with an AIC of 309, demonstrates the best fit among the models
compared. The Spatial Lag model has a higher AIC of 525, followed by the
Spatial Error model at 759, and the OLS regression model at 1435. Since
a lower AIC indicates a better fit, the GWR model appears to be the most
effective in explaining the variance in the data. This suggests that
GWR, which accounts for spatial heterogeneity by allowing model
coefficients to vary across locations, provides a more accurate and
robust fit for this dataset than the other models.
gwrmodel
## Call:
## gwr(formula = LNMEDHVAL ~ PCTVACANT + PCTSINGLES + PCTBACHMOR +
## LNNBELPOV, data = regDatashps, gweight = gwr.Gauss, adapt = bw,
## hatmatrix = TRUE, se.fit = TRUE)
## Kernel function: gwr.Gauss
## Adaptive quantile: 0.00813 (about 13 of 1720 data points)
## Summary of GWR coefficient estimates at data points:
## Min. 1st Qu. Median 3rd Qu. Max. Global
## X.Intercept. 9.67276 10.71432 10.95424 11.17420 12.08314 11.11
## PCTVACANT -0.03174 -0.01424 -0.00896 -0.00358 0.01679 -0.02
## PCTSINGLES -0.02497 -0.00755 -0.00166 0.00423 0.01433 0.00
## PCTBACHMOR 0.00110 0.01014 0.01493 0.02022 0.03473 0.02
## LNNBELPOV -0.23652 -0.07336 -0.04012 -0.01267 0.09488 -0.08
## Number of data points: 1720
## Effective number of parameters (residual: 2traceS - traceS'S): 361
## Effective degrees of freedom (residual: 2traceS - traceS'S): 1359
## Sigma (residual: 2traceS - traceS'S): 0.276
## Effective number of parameters (model: traceS): 258
## Effective degrees of freedom (model: traceS): 1462
## Sigma (model: traceS): 0.266
## Sigma (ML): 0.246
## AICc (GWR p. 61, eq 2.33; p. 96, eq. 4.21): 661
## AIC (GWR p. 96, eq. 4.22): 309
## Residual sum of squares: 104
## Quasi-global R2: 0.848
The choropleth map of local \(R^2\)
values from the GWR model illustrates how the model explains variations
in logged median house values across the city. Darker-colored areas,
such as the northwestern, parts of the northeastern, and far western
regions, indicate a stronger model fit, where the predictors in the
model explain a larger proportion of the variability in house values. In
contrast, lighter-colored areas, particularly in the northern and
western parts of the city, show a weaker model fit, suggesting that the
predictors are less effective in capturing the variability in these
regions.
gwrresults<-as.data.frame(gwrmodel$SDF)
regDatashps$localR2<-gwrresults$localR2
regDatashps_sf <- st_as_sf(regDatashps)
ggplot(data = regDatashps_sf) +
geom_sf(aes(fill = localR2), color = NA) +
scale_fill_gradientn(colors = c("#FAF9F6", "#c44536"),
name = "Local R-Squared",
na.value = "transparent")+
labs(title = "Local R-Squared from GWR", x = "", y = "") +
theme(legend.text = element_text(size = 9),
legend.title = element_text(size = 10),
axis.text.x = element_blank(),
axis.ticks.x = element_blank(),
axis.text.y = element_blank(),
axis.ticks.y = element_blank(),
plot.subtitle = element_text(size = 9, face = "italic"),
plot.title = element_text(size = 12, face = "bold"),
panel.background = element_blank(),
panel.border = element_rect(colour = "grey", fill = NA, size = 0.8))

The analysis indicates that the GWR model has successfully reduced
spatial autocorrelation in the residuals compared to the OLS model. In
the distribution of Moran’s I values for GWR residuals, the observed
Moran’s I is close to zero, suggesting minimal spatial autocorrelation
and aligning with the assumption of uncorrelated residuals. In contrast,
the Moran’s I for the OLS residuals is both positive and statistically
significant, indicating a stronger degree of spatial dependence.
The spatial lag model also reduces spatial autocorrelation in the
residuals, although not as effectively as the GWR model. The spatial
error model performs similarly, but the residuals exhibit slightly more
spatial autocorrelation than those of the GWR model. Overall, these
results suggest that the GWR model provides the best fit in terms of
minimizing spatial autocorrelation, capturing local spatial variations
more precisely than the spatial lag and spatial error models. This
indicates that GWR is particularly effective for modeling spatial
heterogeneity in this dataset.
GWR_moranMc<-moran.mc(gwrresults$gwr.e, queenlist, 999, alternative="two.sided")
GWR_moranMc
##
## Monte-Carlo simulation of Moran I
##
## data: gwrresults$gwr.e
## weights: queenlist
## number of simulations + 1: 1000
##
## statistic = 0.03, observed rank = 992, p-value = 0.02
## alternative hypothesis: two.sided
The Moran’s I scatter plot for the GWR residuals shows minimal
spatial autocorrelation, as indicated by the nearly horizontal trend of
the line, suggesting that the GWR model has successfully addressed much
of the spatial dependency present in the data. This is consistent with
the earlier histogram results, where the Moran’s I value for GWR
residuals was close to zero, further affirming that the model
effectively captures local spatial variations in logged median house
values.
plt7 <- ggplot(data.frame(res = gwrresults$gwr.e), aes(x = res)) +
geom_histogram(bins = 100, fill = "#283d3b") +
geom_vline(xintercept =GWR_moranMc$statistic, color = "#c44536", linetype = 'dashed', size = 1) +
labs(title = "Observed and Permuted Moran's I of GWR Residuals",
subtitle = "Observed Moran's I in Red",
x = "Moran's I",
y = "Count") +
theme_light() +
theme(plot.subtitle = element_text(size = 9,face = "italic"),
plot.title = element_text(size = 12, face = "bold"),
axis.text.x=element_text(size=6),
axis.text.y=element_text(size=6),
axis.title=element_text(size=8))
plt8 <- ggplot(data = data.frame(
residuals = gwrresults$gwr.e,
spatial_lag = lag.listw(queenlist, gwrresults$gwr.e)
), aes(x = residuals, y = spatial_lag)) +
geom_point(color = "#283d3b", alpha = 0.9, size = 0.6) +
geom_smooth(method = "lm", color = "#c44536", se = FALSE) +
labs(title = "Moran's I Scatter Plot for GWR Residuals",
x = "Logged Median House Value",
y = "Spatial Lag of LNMEDHVAL") +
theme_light() +
theme(plot.subtitle = element_text(size = 9,face = "italic"),
plot.title = element_text(size = 12, face = "bold"),
axis.text.x=element_text(size=6),
axis.text.y=element_text(size=6),
axis.title=element_text(size=8))
plt7 + plt8

Looking at each predictors in detail, the vacancy rate generally has
a negative impact on housing values, with significant negative effects
observed in Center City, northwestern areas, parts of the northeastern
region, and the western part of the city. However, there is a localized
area in southern Center City where vacancy rates unexpectedly have a
positive impact on housing values.
Single-family housing, in general, positively impacts housing values,
particularly in the far northeast and far northwest areas, where this
effect is more pronounced. Conversely, in some parts of the city—such as
eastern Philadelphia, parts of the west, and sections of the south—the
impact of single-family housing is negative and statistically
significant.
The percentage of residents with a bachelor’s degree generally has a
positive impact on housing values, with no areas showing a negative
relationship across the city. This positive influence is especially
statistically significant in the northern and northeastern parts of the
city.
Finally, the poverty rate generally has a negative effect on housing
values. This effect is more statistically significant in the southern,
eastern, and northwestern parts of the city.
Overall, these spatial variations highlight how different factors
affect housing values uniquely across Philadelphia, emphasizing the
importance of localized analysis in understanding property dynamics.
regDatashps_sf$coefPCTVACANTst_cat <- cut(regDatashps_sf$coefPCTVACANTst,
breaks = c(-Inf, -2, 0, 2, Inf),
labels = c("< -2", "-2 to 0", "0 to 2", "> 2"))
regDatashps_sf$coefPCTSINGLESst_cat <- cut(regDatashps_sf$coefPCTSINGLESst,
breaks = c(-Inf, -2, 0, 2, Inf),
labels = c("< -2", "-2 to 0", "0 to 2", "> 2"))
regDatashps_sf$coefPCTBACHMORst_cat <- cut(regDatashps_sf$coefPCTBACHMORst,
breaks = c(-Inf, -2, 0, 2, Inf),
labels = c("< -2", "-2 to 0", "0 to 2", "> 2"))
regDatashps_sf$coefLNNBELPOVst_cat <- cut(regDatashps_sf$coefLNNBELPOVst,
breaks = c(-Inf, -2, 0, 2, Inf),
labels = c("< -2", "-2 to 0", "0 to 2", "> 2"))
p1 <- ggplot(regDatashps_sf) +
geom_sf(aes(fill = coefPCTVACANTst_cat), color = NA) +
scale_fill_manual(
values = c("#c44536", "#f1b1a6", "#8fa7a5", "#283d3b"),
name = "Ratio Category"
) +
labs(title = "PCTVACANT Coefficient to Standard Error",
x = "", y = "") +
theme(legend.text = element_text(size = 9),
legend.title = element_text(size = 10),
axis.text.x = element_blank(),
axis.ticks.x = element_blank(),
axis.text.y = element_blank(),
axis.ticks.y = element_blank(),
plot.subtitle = element_text(size = 9, face = "italic"),
plot.title = element_text(size = 12, face = "bold"),
panel.background = element_blank(),
panel.border = element_rect(colour = "grey", fill = NA, size = 0.8))
p2 <- ggplot(regDatashps_sf) +
geom_sf(aes(fill = coefPCTSINGLESst_cat), color = NA) +
scale_fill_manual(
values = c("#c44536", "#f1b1a6", "#8fa7a5", "#283d3b"),
name = "Ratio Category"
) +
labs(title = "PCTSINGLES Coefficient to Standard Error",
x = "", y = "") +
theme(legend.text = element_text(size = 9),
legend.title = element_text(size = 10),
axis.text.x = element_blank(),
axis.ticks.x = element_blank(),
axis.text.y = element_blank(),
axis.ticks.y = element_blank(),
plot.subtitle = element_text(size = 9, face = "italic"),
plot.title = element_text(size = 12, face = "bold"),
panel.background = element_blank(),
panel.border = element_rect(colour = "grey", fill = NA, size = 0.8))
p3 <- ggplot(regDatashps_sf) +
geom_sf(aes(fill = coefPCTBACHMORst_cat), color = NA) +
scale_fill_manual(
values = c("#c44536", "#f1b1a6", "#8fa7a5", "#283d3b"),
name = "Ratio Category"
) +
labs(title = "PCTBACHMOR Coefficient to Standard Error",
x = "", y = "") +
theme(legend.text = element_text(size = 9),
legend.title = element_text(size = 10),
axis.text.x = element_blank(),
axis.ticks.x = element_blank(),
axis.text.y = element_blank(),
axis.ticks.y = element_blank(),
plot.subtitle = element_text(size = 9, face = "italic"),
plot.title = element_text(size = 12, face = "bold"),
panel.background = element_blank(),
panel.border = element_rect(colour = "grey", fill = NA, size = 0.8))
p4 <- ggplot(regDatashps_sf) +
geom_sf(aes(fill = coefLNNBELPOVst_cat), color = NA) +
scale_fill_manual(
values = c("#c44536", "#f1b1a6", "#8fa7a5", "#283d3b"),
name = "Ratio Category"
) +
labs(title = "LNNBELPOV Coefficient to Standard Error",
x = "", y = "") +
theme(legend.text = element_text(size = 9),
legend.title = element_text(size = 10),
axis.text.x = element_blank(),
axis.ticks.x = element_blank(),
axis.text.y = element_blank(),
axis.ticks.y = element_blank(),
plot.subtitle = element_text(size = 9, face = "italic"),
plot.title = element_text(size = 12, face = "bold"),
panel.background = element_blank(),
panel.border = element_rect(colour = "grey", fill = NA, size = 0.8))
p1 + p2 + p3 + p4 +
plot_layout(ncol = 2)

LS0tCnRpdGxlOiAiVXNpbmcgR2VvZ3JhcGhpY2FsbHkgV2VpZ2h0ZWQgUmVncmVzc2lvbiwgU3BhdGlhbCBMYWcsIGFuZCBTcGF0aWFsIEVycm9yIHRvIFByZWRpY3QgTWVkaWFuIEhvdXNlIFZhbHVlcyBpbiBQaGlsYWRlbHBoaWEiCmF1dGhvcjogIkVtaWx5IFpob3UsIFppeWkgR3VvLCBFbW1hIEppYW5nIgpkYXRlOiAiYHIgU3lzLkRhdGUoKWAiCm91dHB1dDoKICBodG1sX2RvY3VtZW50OgogICAgdGhlbWU6IHNpbXBsZXgKICAgIHRvYzogeWVzCiAgICB0b2NfZmxvYXQ6IHllcwogICAgY29kZV9mb2xkaW5nOiBoaWRlCiAgICBjb2RlX2Rvd25sb2FkOiB5ZXMKCmVkaXRvcl9vcHRpb25zOgogIG1hcmtkb3duOgogICAgd3JhcDogc2VudGVuY2UKLS0tCgpWZXJzaW9uIDIuMCB8IEZpcnN0IENyZWF0ZWQgT2N0IDIyLCAyMDI0IHwgVXBkYXRlZCBOb3YgMiwgMjAyNAoKS2V5d29yZHM6IFNwYXRpYWwgRXJyb3IsIFNwYXRpYWwgTGFnLCBHZW9ncmFwaGljYWxseSBXZWlnaHRlZCBSZWdyZXNzaW9uLCBHbG9iYWwgJiBMb2NhbCBNb3JhbidzIEksIEFrYWlraSBJbmZvcm1hdGlvbiBDcml0ZXJpb24sIFNjaHdhcnogQ3JpdGVyaW9uLCBMb2cgTGlrZWxpaG9vZCwgTGlrZWxpaG9vZCBSYXRpbyBUZXN0CgpHaXRIdWIgUmVwb3NpdG9yeTogW0NQTE42NzEtR1ctUmVncmVzc2lvbl0oaHR0cHM6Ly9naXRodWIuY29tL2VtaWx5emhvdTExMi9DUExONjcxLUdXLVJlZ3Jlc3Npb24pCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFKQpgYGAKCgpgYGB7ciBsb2FkIHBhY2thZ2VzLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBpbmNsdWRlPUZBTFNFfQoKb3B0aW9ucyhzY2lwZW49OTk5KQpvcHRpb25zKGRpZ2l0cyA9IDMpCgojIExpc3Qgb2YgcmVxdWlyZWQgcGFja2FnZXMKcGFja2FnZXMgPC0gYygidGlkeXZlcnNlIiwgInNmIiwgImhlcmUiLCAic3BkZXAiLCAic3Bnd3IiLCAic3BhdGlhbHJlZyIsIAogICAgICAgICAgICAgICJ3aGl0ZXN0cmFwIiwgImxtdGVzdCIsICJ0c2VyaWVzIiwgImdncGxvdDIiLCAia2FibGVFeHRyYSIsICJwYXRjaHdvcmsiKQoKIyBJbnN0YWxsIGFuZCBsb2FkIHJlcXVpcmVkIHBhY2thZ2VzCnBhY2thZ2UuY2hlY2sgPC0gbGFwcGx5KAogIHBhY2thZ2VzLAogIEZVTiA9IGZ1bmN0aW9uKHgpIHsKICAgIGlmICghcmVxdWlyZSh4LCBjaGFyYWN0ZXIub25seSA9IFRSVUUpKSB7CiAgICAgIGluc3RhbGwucGFja2FnZXMoeCwgZGVwZW5kZW5jaWVzID0gVFJVRSwgcXVpZXRseT1UUlVFKQogICAgICBsaWJyYXJ5KHgsIGNoYXJhY3Rlci5vbmx5ID0gVFJVRSkKICAgIH0KICB9CikKCmBgYAoKCmBgYHtyIGxvYWQgZGF0YSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgaW5jbHVkZT1GQUxTRX0KCnJlZ0RhdGEgPC0gc3RfcmVhZChoZXJlKCJkYXRhIiwgIlJlZ3Jlc3Npb25EYXRhLnNocCIpKQoKYGBgCgojIEludHJvZHVjdGlvbgoKUGhpbGFkZWxwaGlhJ3MgaG91c2luZyBtYXJrZXQgaGFzIHVuZGVyZ29uZSBzaWduaWZpY2FudCB0cmFuc2Zvcm1hdGlvbnMgaW4gcmVjZW50IHllYXJzLCB3aXRoIHJpc2luZyBwcm9wZXJ0eSB2YWx1ZXMgY3JlYXRpbmcgdXJnZW50IGNvbmNlcm5zIGZvciB1cmJhbiBwbGFubmVycywgcG9saWN5bWFrZXJzLCBhbmQgcmVzaWRlbnRzIGFsaWtlLiBUaGlzIHVwd2FyZCB0cmVuZCBoYXMgaW50ZW5zaWZpZWQgaXNzdWVzIG9mIGhvdXNpbmcgYWZmb3JkYWJpbGl0eSwgZGlzcHJvcG9ydGlvbmF0ZWx5IGltcGFjdGluZyBsb3ctIGFuZCBtaWRkbGUtaW5jb21lIGhvdXNlaG9sZHMuIFRoZSByYXBpZCBpbmNyZWFzZSBpbiBob3VzaW5nIHZhbHVlcyBoYXMgc3B1cnJlZCBnZW50cmlmaWNhdGlvbiwgZGlzcGxhY2luZyBsb25nLXRlcm0gcmVzaWRlbnRzIGFuZCByZXNoYXBpbmcgdGhlIHNvY2lvLWVjb25vbWljIGZhYnJpYyBvZiB2YXJpb3VzIG5laWdoYm9yaG9vZHMgYWNyb3NzIHRoZSBjaXR5LiBBcyByZXNlYXJjaGVycyBoYXZlIG9ic2VydmVkLCBnZW50cmlmaWNhdGlvbiBvZnRlbiBsZWFkcyB0byBzb2NpYWwgZGlzcGxhY2VtZW50LCBleGFjZXJiYXRpbmcgaW5lcXVhbGl0eSBhcyBob3VzaW5nIGFmZm9yZGFiaWxpdHkgZGVjbGluZXMgKEZyZWVtYW4gJiBCcmFjb25pLCAyMDA0OyBBdGtpbnNvbiwgMjAwNCkuIFVuZGVyc3RhbmRpbmcgdGhlIGZhY3RvcnMgZHJpdmluZyB0aGVzZSBzaGlmdHMgaW4gcHJvcGVydHkgdmFsdWVzIGlzIGVzc2VudGlhbCBmb3IgYWRkcmVzc2luZyBhZmZvcmRhYmlsaXR5IGNoYWxsZW5nZXMsIHByb21vdGluZyBuZWlnaGJvcmhvb2Qgc3RhYmlsaXR5LCBhbmQgZm9zdGVyaW5nIGVxdWl0YWJsZSBkZXZlbG9wbWVudCBpbiBQaGlsYWRlbHBoaWEgKExlZXMsIDIwMDgpLgoKSW4gYSBwcmV2aW91cyBzdHVkeSwgT3JkaW5hcnkgTGVhc3QgU3F1YXJlcyAoT0xTKSByZWdyZXNzaW9uIHdhcyBlbXBsb3llZCB0byBleHBsb3JlIHRoZSByZWxhdGlvbnNoaXBzIGJldHdlZW4gbWVkaWFuIGhvdXNlIHZhbHVlcywgdGhlIGRlcGVuZGVudCB2YXJpYWJsZSwgYW5kIHNldmVyYWwga2V5IHNvY2lvLWVjb25vbWljIHByZWRpY3RvcnMuIFRoZXNlIHByZWRpY3RvcnMgaW5jbHVkZWQgZWR1Y2F0aW9uYWwgYXR0YWlubWVudCwgdmFjYW5jeSByYXRlcywgdGhlIHByb3BvcnRpb24gb2YgZGV0YWNoZWQgc2luZ2xlLWZhbWlseSBob21lcywgYW5kIHBvdmVydHkgbGV2ZWxzLiBFYWNoIHZhcmlhYmxlIHdhcyBjaG9zZW4gZm9yIGl0cyBlc3RhYmxpc2hlZCBpbmZsdWVuY2Ugb24gaG91c2luZyBtYXJrZXRzIGFuZCBpdHMgYWJpbGl0eSB0byBzaGVkIGxpZ2h0IG9uIHVuZGVybHlpbmcgc29jaW8tZWNvbm9taWMgY29uZGl0aW9ucyB0aGF0IG1heSBzaGFwZSBwcm9wZXJ0eSB2YWx1ZXMuIEZvciBpbnN0YW5jZSwgZWR1Y2F0aW9uYWwgYXR0YWlubWVudCBpcyBwb3NpdGl2ZWx5IGFzc29jaWF0ZWQgd2l0aCBlY29ub21pYyBwcm9zcGVyaXR5IGFuZCBob3VzaW5nIGRlbWFuZCwgYXMgYXJlYXMgd2l0aCBoaWdoZXIgZWR1Y2F0aW9uYWwgbGV2ZWxzIG9mdGVuIGJlbmVmaXQgZnJvbSBoaWdoZXIgaW5jb21lcyBhbmQgZ3JlYXRlciBpbnZlc3RtZW50IFZhY2FuY3kgcmF0ZXMsIG9uIHRoZSBvdGhlciBoYW5kLCBhcmUgdHlwaWNhbGx5IGxpbmtlZCB0byBuZWlnaGJvcmhvb2QgZGVjbGluZSBhbmQgcmVkdWNlZCBwcm9wZXJ0eSB2YWx1ZXMsIGFzIHZhY2FudCBwcm9wZXJ0aWVzIHNpZ25hbCBlY29ub21pYyBkaXN0cmVzcywgZGlzY291cmFnZSBpbnZlc3RtZW50LCBhbmQgbWF5IGNvbnRyaWJ1dGUgdG8gaGlnaGVyIGNyaW1lIHJhdGVzIChNYWxsYWNoLCAyMDE4KS4gVGhlIGhvdXNpbmcgbWFya2V0IHByZWZlcmVuY2UgZm9yIHNpbmdsZS1mYW1pbHkgaG9tZXMsIHdoaWNoIG9mZmVyIGdyZWF0ZXIgc3BhY2UgYW5kIHByaXZhY3ksIGlzIHdlbGwtZG9jdW1lbnRlZCBpbiB0aGUgbGl0ZXJhdHVyZSAoR2xhZXNlciAmIEd5b3Vya28sIDIwMTgpLCB3aGlsZSByZXNlYXJjaCBjb25zaXN0ZW50bHkgZGVtb25zdHJhdGVzIGEgbmVnYXRpdmUgY29ycmVsYXRpb24gYmV0d2VlbiBwb3ZlcnR5IGxldmVscyBhbmQgaG91c2luZyB2YWx1ZXMsIHdpdGggaGlnaGVyIHBvdmVydHkgcmF0ZXMgb2Z0ZW4gbGlua2VkIHRvIGRlY3JlYXNlZCBkZW1hbmQgYW5kIHVuZGVyaW52ZXN0bWVudCBpbiBsb2NhbCBpbmZyYXN0cnVjdHVyZSAoR2Fsc3RlciwgMjAwOCkuCgpBbHRob3VnaCBPTFMgcmVncmVzc2lvbiBwcm92aWRlcyBhIGZvdW5kYXRpb25hbCB1bmRlcnN0YW5kaW5nIG9mIHRoZXNlIHJlbGF0aW9uc2hpcHMsIGl0IGhhcyBsaW1pdGF0aW9ucyB3aGVuIGFwcGxpZWQgdG8gc3BhdGlhbCBkYXRhLCBhcyBpdCBhc3N1bWVzIGluZGVwZW5kZW5jZSBiZXR3ZWVuIG9ic2VydmF0aW9ucyBhbmQgaWdub3JlcyBwb3RlbnRpYWwgc3BhdGlhbCBkZXBlbmRlbmNpZXMuIEhvdXNpbmcgdmFsdWVzIGluIG9uZSBhcmVhIGFyZSBvZnRlbiBpbmZsdWVuY2VkIGJ5IHRob3NlIGluIG5lYXJieSBhcmVhcywgcmVzdWx0aW5nIGluIHNwYXRpYWwgYXV0b2NvcnJlbGF0aW9uIHRoYXQgY2FuIGxlYWQgdG8gYmlhc2VkIG9yIG1pc2xlYWRpbmcgcmVzdWx0cyB3aGVuIHVzaW5nIHRyYWRpdGlvbmFsIE9MUyBtZXRob2RzLiBTcGF0aWFsIGF1dG9jb3JyZWxhdGlvbiByZWZsZWN0cyBUb2JsZXLigJlzIEZpcnN0IExhdyBvZiBHZW9ncmFwaHksIHdoaWNoIHN0YXRlcyB0aGF0IOKAnGV2ZXJ5dGhpbmcgaXMgcmVsYXRlZCB0byBldmVyeXRoaW5nIGVsc2UsIGJ1dCBuZWFyIHRoaW5ncyBhcmUgbW9yZSByZWxhdGVkIHRoYW4gZGlzdGFudCB0aGluZ3PigJ0gKFRvYmxlciwgMTk3MCkuIFdoZW4gc3BhdGlhbCBkZXBlbmRlbmNpZXMgYXJlIGlnbm9yZWQsIGFzIGlzIHRoZSBjYXNlIGluIE9MUyByZWdyZXNzaW9uLCB0aGUgZXN0aW1hdGVzIG1heSBzdWZmZXIgZnJvbSBvbWl0dGVkIHZhcmlhYmxlIGJpYXMsIHlpZWxkaW5nIGluYWNjdXJhdGUgY29uY2x1c2lvbnMgYWJvdXQgdGhlIHJlbGF0aW9uc2hpcHMgYmV0d2VlbiB2YXJpYWJsZXMgKEFuc2VsaW4sIDE5ODgpLgoKVG8gYWRkcmVzcyB0aGVzZSBsaW1pdGF0aW9ucywgdGhpcyByZXBvcnQgYXBwbGllcyBzcGF0aWFsIGVjb25vbWV0cmljIHRlY2huaXF1ZXMsIHNwZWNpZmljYWxseSBzcGF0aWFsIGxhZywgc3BhdGlhbCBlcnJvciwgYW5kIGdlb2dyYXBoaWNhbGx5IHdlaWdodGVkIHJlZ3Jlc3Npb24gKEdXUikgbW9kZWxzLCB0byBtb3JlIGFjY3VyYXRlbHkgY2FwdHVyZSB0aGUgc3BhdGlhbCBkZXBlbmRlbmNpZXMgYWZmZWN0aW5nIGhvdXNpbmcgdmFsdWVzIGluIFBoaWxhZGVscGhpYS4gVGhlIHNwYXRpYWwgbGFnIG1vZGVsIGluY29ycG9yYXRlcyB0aGUgaW5mbHVlbmNlIG9mIG5laWdoYm9yaW5nIHZhbHVlcyBkaXJlY3RseSBpbnRvIHRoZSByZWdyZXNzaW9uLCBhbGxvd2luZyBmb3IgYW4gdW5kZXJzdGFuZGluZyBvZiBob3cgaG91c2luZyB2YWx1ZXMgaW4gb25lIGFyZWEgbWF5IGFmZmVjdCB0aG9zZSBpbiBhZGphY2VudCBhcmVhcyAoTGVTYWdlICYgUGFjZSwgMjAwOSkuIFRoZSBzcGF0aWFsIGVycm9yIG1vZGVsIGFjY291bnRzIGZvciBzcGF0aWFsIGF1dG9jb3JyZWxhdGlvbiBpbiB0aGUgcmVzaWR1YWxzLCBpc29sYXRpbmcgdW5vYnNlcnZlZCBzcGF0aWFsbHkgY29ycmVsYXRlZCBmYWN0b3JzIHRoYXQgbWF5IGluZmx1ZW5jZSBob3VzaW5nIHZhbHVlcyAoQW5zZWxpbiwgMTk4OCkuIExhc3RseSwgdGhlIGdlb2dyYXBoaWNhbGx5IHdlaWdodGVkIHJlZ3Jlc3Npb24gKEdXUikgbW9kZWwgb2ZmZXJzIGEgbG9jYWxpemVkIHBlcnNwZWN0aXZlLCBhbGxvd2luZyBjb2VmZmljaWVudHMgdG8gdmFyeSBieSBsb2NhdGlvbiBhbmQgY2FwdHVyaW5nIHRoZSBoZXRlcm9nZW5laXR5IG9mIHJlbGF0aW9uc2hpcHMgYWNyb3NzIGRpZmZlcmVudCBuZWlnaGJvcmhvb2RzIChCcnVuc2RvbiwgRm90aGVyaW5naGFtLCAmIENoYXJsdG9uLCAxOTk2KS4gQnkgZW1wbG95aW5nIHRoZXNlIHNwYXRpYWwgdGVjaG5pcXVlcywgdGhpcyBzdHVkeSBhaW1zIHRvIGVuaGFuY2UgdGhlIGFjY3VyYWN5IG9mIHRoZSBpbml0aWFsIE9MUyBmaW5kaW5ncyBhbmQgcHJvdmlkZSBhIG1vcmUgY29tcHJlaGVuc2l2ZSB1bmRlcnN0YW5kaW5nIG9mIHRoZSBzb2Npby1lY29ub21pYyBhbmQgc3BhdGlhbCBmYWN0b3JzIGluZmx1ZW5jaW5nIGhvdXNpbmcgdmFsdWVzLiBUaGVzZSBpbnNpZ2h0cyB3aWxsIHN1cHBvcnQgbW9yZSBlZmZlY3RpdmUgcG9saWN5IGludGVydmVudGlvbnMgYW5kIHVyYmFuIGRldmVsb3BtZW50IHN0cmF0ZWdpZXMgYWltZWQgYXQgYWNoaWV2aW5nIGVxdWl0YWJsZSBhbmQgc3VzdGFpbmFibGUgZ3Jvd3RoIGluIFBoaWxhZGVscGhpYS4KCiMgTWV0aG9kcyAKCiMjIFNwYXRpYWwgQXV0b2NvcnJlbGF0aW9uCgpUaGUgRmlyc3QgTGF3IG9mIEdlb2dyYXBoeSwgcHJvcG9zZWQgYnkgV2FsZG8gVG9ibGVyLCBzdGF0ZXMgdGhhdCAqImV2ZXJ5dGhpbmcgaXMgcmVsYXRlZCB0byBldmVyeXRoaW5nIGVsc2UsIGJ1dCBuZWFyZXIgdGhpbmdzIGFyZSBtb3JlIHJlbGF0ZWQgdGhhbiBkaXN0YW50IHRoaW5ncy4iKiBUaGlzIGxhdyBjYXB0dXJlcyB0aGUgcHJpbmNpcGxlIG9mIHNwYXRpYWwgZGVwZW5kZW5jZSwgd2hpY2ggdW5kZXJwaW5zIG1hbnkgc3BhdGlhbCBhbmFseXNlcywgaW5jbHVkaW5nIHNwYXRpYWwgcmVncmVzc2lvbiBtb2RlbHMuIE9uZSB3YXkgdG8gbWVhc3VyZSBzcGF0aWFsIGRlcGVuZGVuY2UgaXMgdGhyb3VnaCBNb3JhbidzIEksIGEgc3RhdGlzdGljIHRoYXQgcXVhbnRpZmllcyBzcGF0aWFsIGF1dG9jb3JyZWxhdGlvbi4gTW9yYW4ncyBJIGZvciBhIHZhcmlhYmxlIGlzIGNhbGN1bGF0ZWQgYXMgZm9sbG93czogCgoKJCQKSSA9IFxmcmFje259e1xzdW1fe2k9MX1ee259IFxzdW1fe2o9MX1ee259IHdfe2lqfX0gXGNkb3QgXGZyYWN7XHN1bV97aT0xfV57bn0gXHN1bV97aj0xfV57bn0gd197aWp9IChYX2kgLSBcYmFye1h9KShYX2ogLSBcYmFye1h9KX17XHN1bV97aT0xfV57bn0gKFhfaSAtIFxiYXJ7WH0pXjJ9CiQkCndoZXJlICRuJCBpcyB0aGUgbnVtYmVyIG9mIG9ic2VydmF0aW9ucywgJFhfaSQgYW5kICRYX2okIGFyZSB0aGUgdmFsdWVzIG9mIHRoZSB2YXJpYWJsZSBhdCBsb2NhdGlvbnMgJGkkIGFuZCAkaiQsIHJlc3BlY3RpdmVseSwgJFxiYXJ7WH0kIGlzIHRoZSBtZWFuIG9mIHRoZSB2YXJpYWJsZSwgYW5kICR3X3tpan0kIGlzIHRoZSBzcGF0aWFsIHdlaWdodCBiZXR3ZWVuIGxvY2F0aW9ucyAkaSQgYW5kICRqJC4KCkhlcmUsIHdlIHVzZSBhIHNwYXRpYWwgd2VpZ2h0IG1hdHJpeCBjb25zdHJ1Y3RlZCB1c2luZyBhICJRdWVlbiIgY29udGlndWl0eSBtZXRob2QsIHdoaWNoIGRlZmluZXMgZWFjaCB1bml0J3MgbmVpZ2hib3JzIGJhc2VkIG9uIHNoYXJlZCBib3VuZGFyaWVzIG9yIHZlcnRpY2VzLiBUaGlzIG1hdHJpeCByZW1haW5zIGNvbnNpc3RlbnQgYWNyb3NzIHRoZSBhbmFseXNpcywgYWx0aG91Z2ggc3RhdGlzdGljaWFucyBtYXkgdXNlIGRpZmZlcmVudCB3ZWlnaHQgbWF0cmljZXMgdG8gYXNzZXNzIG1vZGVsIHNlbnNpdGl2aXR5IHRvIG5laWdoYm9yIGRlZmluaXRpb25zLgoKVGVzdGluZyB0aGUgc2lnbmlmaWNhbmNlIG9mIHNwYXRpYWwgYXV0b2NvcnJlbGF0aW9uIGludm9sdmVzIGV2YWx1YXRpbmcgd2hldGhlciB0aGUgb2JzZXJ2ZWQgTW9yYW4ncyBJIGRpZmZlcnMgZnJvbSB3aGF0IHdvdWxkIGJlIGV4cGVjdGVkIHVuZGVyIHNwYXRpYWwgcmFuZG9tbmVzcy4gSW4gaHlwb3RoZXNpcyB0ZXN0aW5nLCB0aGUgbnVsbCBoeXBvdGhlc2lzIChcKCBIXzAgXCkpIGlzIHRoYXQgdGhlcmUgaXMgbm8gc3BhdGlhbCBhdXRvY29ycmVsYXRpb24sIHdoaWxlIHRoZSBhbHRlcm5hdGl2ZSAoXCggSF9hIFwpKSAgcG9zaXRzIHRoZSBwcmVzZW5jZSBvZiBzcGF0aWFsIGF1dG9jb3JyZWxhdGlvbi4gVXNpbmcgcmFuZG9tIHBlcm11dGF0aW9ucyBvZiBkYXRhIHZhbHVlcyBhY3Jvc3MgbG9jYXRpb25zLCB3ZSBnZW5lcmF0ZSBhIHJlZmVyZW5jZSBkaXN0cmlidXRpb24gb2YgTW9yYW4ncyBJIHVuZGVyIHRoZSBudWxsIGh5cG90aGVzaXMgYW5kIGNvbXBhcmUgdGhlIG9ic2VydmVkIHN0YXRpc3RpYyB0byB0aGlzIGRpc3RyaWJ1dGlvbi4KCkJleW9uZCBnbG9iYWwgc3BhdGlhbCBhdXRvY29ycmVsYXRpb24gbWVhc3VyZWQgYnkgTW9yYW4ncyBJLCBsb2NhbCBzcGF0aWFsIGF1dG9jb3JyZWxhdGlvbiBpZGVudGlmaWVzIHNwZWNpZmljIGFyZWFzIHdpdGggY2x1c3RlcmluZyBvciBkaXNwZXJzaW9uLiBUaGUgc2lnbmlmaWNhbmNlIG9mIGxvY2FsIE1vcmFuJ3MgSSBpcyB0ZXN0ZWQgc2ltaWxhcmx5IHVzaW5nIHJhbmRvbSBwZXJtdXRhdGlvbnMsIGFuZCByZXN1bHRzIGNhbiBoaWdobGlnaHQgc3RhdGlzdGljYWxseSBzaWduaWZpY2FudCBjbHVzdGVycyBvciBvdXRsaWVycyB0aGF0IGdsb2JhbCBtZWFzdXJlcyBtaWdodCBtaXNzLgoKIyMgT3JkaW5hcnkgTGVhc3QgU3F1YXJlcyBSZWdyZXNzaW9uCgpPcmRpbmFyeSBMZWFzdCBTcXVhcmVzIChPTFMpIHJlZ3Jlc3Npb24gaXMgYSBzdGF0aXN0aWNhbCB0ZWNobmlxdWUgZm9yIGVzdGltYXRpbmcgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIGEgZGVwZW5kZW50IHZhcmlhYmxlIGFuZCBvbmUgb3IgbW9yZSBpbmRlcGVuZGVudCB2YXJpYWJsZXMgYnkgbWluaW1pemluZyB0aGUgc3F1YXJlZCBkaWZmZXJlbmNlcyBiZXR3ZWVuIG9ic2VydmVkIGFuZCBwcmVkaWN0ZWQgdmFsdWVzLiBLZXkgYXNzdW1wdGlvbnMgb2YgT0xTIGluY2x1ZGUgbGluZWFyaXR5LCBpbmRlcGVuZGVuY2Ugb2Ygb2JzZXJ2YXRpb25zLCBob21vc2NlZGFzdGljaXR5IChjb25zdGFudCBlcnJvciB2YXJpYW5jZSksIG5vcm1hbGl0eSBvZiBlcnJvcnMsIGFuZCBubyBtdWx0aWNvbGxpbmVhcml0eSBhbW9uZyBwcmVkaWN0b3JzLgoKSW4gb3VyIGZpcnN0IGFzc2lnbm1lbnQsIHdlIHVzZWQgT0xTIHJlZ3Jlc3Npb24gdG8gYXNzZXNzIGhvdyB2YWNhbmN5IHJhdGVzLCBzaW5nbGUtZmFtaWx5IGhvdXNpbmcgcGVyY2VudGFnZSwgZWR1Y2F0aW9uYWwgYXR0YWlubWVudCwgYW5kIHBvdmVydHkgbGV2ZWxzIGluZmx1ZW5jZSBtZWRpYW4gaG91c2UgdmFsdWUuIEFsbCBwcmVkaWN0b3JzIHdlcmUgc3RhdGlzdGljYWxseSBzaWduaWZpY2FudCwgd2l0aCB2YWNhbmN5IHJhdGVzIGFuZCBwb3ZlcnR5IGxldmVscyBuZWdhdGl2ZWx5IGFmZmVjdGluZyBob3VzZSB2YWx1ZXMsIHdoaWxlIHNpbmdsZS1mYW1pbHkgaG91c2luZyBhbmQgZWR1Y2F0aW9uYWwgYXR0YWlubWVudCBoYWQgcG9zaXRpdmUgZWZmZWN0cy4gVGhlIG1vZGVs4oCZcyBcKFJeMlwpIHdhcyAwLjY2LCBleHBsYWluaW5nIDY2JSBvZiB0aGUgdmFyaWFuY2UgaW4gaG91c2UgdmFsdWVzLiBIb3dldmVyLCBzb21lIHByZWRpY3RvcnMgZXhoaWJpdGVkIG5vbi1saW5lYXIgcGF0dGVybnMsIGFuZCBzcGF0aWFsIGF1dG9jb3JyZWxhdGlvbiBzdWdnZXN0ZWQgZGVwZW5kZW5jZSBhbW9uZyBvYnNlcnZhdGlvbnMsIGluZGljYXRpbmcgdGhhdCBmdXR1cmUgbW9kZWxzIGNvdWxkIGJlbmVmaXQgZnJvbSBzcGF0aWFsIHJlZ3Jlc3Npb24gdGVjaG5pcXVlcy4KCldoZW4gZGF0YSBoYXMgYSBzcGF0aWFsIGNvbXBvbmVudCwgdGhlIGFzc3VtcHRpb24gdGhhdCBlcnJvcnMgYXJlIHJhbmRvbSBhbmQgaW5kZXBlbmRlbnQgb2Z0ZW4gZG9lc27igJl0IGhvbGQsIGFzIG5lYXJieSBvYnNlcnZhdGlvbnMgbWF5IGV4aGliaXQgc2ltaWxhciBlcnJvciBwYXR0ZXJucy4gVG8gdGVzdCB0aGlzLCB3ZSBjYW4gZXhhbWluZSB0aGUgc3BhdGlhbCBhdXRvY29ycmVsYXRpb24gb2YgdGhlIHJlc2lkdWFscyB1c2luZyBNb3JhbuKAmXMgSSwgd2hpY2ggcXVhbnRpZmllcyB0aGUgZGVncmVlIG9mIGNsdXN0ZXJpbmcgaW4gcmVzaWR1YWxzLiBBbm90aGVyIGFwcHJvYWNoIGlzIHRvIHJlZ3Jlc3MgdGhlIHJlc2lkdWFscyBvbiBuZWFyYnkgcmVzaWR1YWxzIGZyb20gbmVpZ2hib3JpbmcgYXJlYXMsIHN1Y2ggYXMgYmxvY2sgZ3JvdXBzIGRlZmluZWQgYnkgdGhlIFF1ZWVuIG1hdHJpeCwgdG8gaWRlbnRpZnkgYW55IHNwYXRpYWwgZGVwZW5kZW5jZS4gVGhlc2UgdGVzdHMgaGVscCBkZXRlcm1pbmUgaWYgc3BhdGlhbCBhdXRvY29ycmVsYXRpb24gaXMgcHJlc2VudCwgaW5kaWNhdGluZyBhIG5lZWQgZm9yIHNwYXRpYWwgcmVncmVzc2lvbiB0ZWNobmlxdWVzLgoKSW4gUiwgdGhlcmUgYXJlIG1ldGhvZHMgdG8gdGVzdCBvdGhlciBrZXkgcmVncmVzc2lvbiBhc3N1bXB0aW9ucy4gRm9yIGhvbW9zY2VkYXN0aWNpdHkgKGNvbnN0YW50IGVycm9yIHZhcmlhbmNlKSwgd2hpY2ggaXMgcmVsYXRlZCB0byB0aGUgaW5kZXBlbmRlbmNlIG9mIGVycm9ycywgd2UgdXNlIHRoZSAqKkJyZXVzY2gtUGFnYW4gVGVzdCoqLCB0aGUgKipLb2Vua2VyLUJhc3NldHQgVGVzdCoqLCBhbmQgdGhlICoqV2hpdGUgVGVzdCoqLiBUaGUgbnVsbCBoeXBvdGhlc2lzIChcKCBIXzAgXCkpIGlzIHRoYXQgZXJyb3JzIGFyZSBob21vc2NlZGFzdGljLCB3aGlsZSB0aGUgYWx0ZXJuYXRpdmUgaHlwb3RoZXNpcyAoXCggSF9hIFwpKSBpcyB0aGF0IGVycm9ycyBleGhpYml0IGhldGVyb3NjZWRhc3RpY2l0eS4gRm9yIG5vcm1hbGl0eSBvZiBlcnJvcnMsIHdlIGNhbiB1c2UgdGhlICoqSmFycXVlLUJlcmEgdGVzdCoqLiBUaGUgbnVsbCBoeXBvdGhlc2lzIGlzIHRoYXQgcmVzaWR1YWxzIGFyZSBub3JtYWwsIGFuZCB0aGUgYWx0ZXJuYXRpdmUgaHlwb3RoZXNpcyBpcyB0aGF0IHRoZXkgYXJlIG5vdCBub3JtYWwuIFdlIHdhbnQgdG8gbm90IGJlIGFibGUgdG8gcmVqZWN0IHRoZSBudWxsIGh5cG90aGVzaXMgKGkuZS4sIGdldCBhIHAtdmFsdWUgb2YgMC4wNSBvciBoaWdoZXIpLgoKCiMjIFNwYXRpYWwgTGFnIGFuZCBTcGF0aWFsIEVycm9yIFJlZ3Jlc3Npb24KCkluIHRoaXMgcmVwb3J0LCB3ZSB1c2UgUiB0byBydW4gc3BhdGlhbCBsYWcgYW5kIHNwYXRpYWwgZXJyb3IgcmVncmVzc2lvbnMuIEFtb25nIHRoZSB0d28gbWV0aG9kcywgc3BhdGlhbCBsYWcgcmVncmVzc2lvbiBhc3N1bWVzIHRoZSB2YWx1ZSBvZiB0aGUgZGVwZW5kZW50IHZhcmlhYmxlIGF0IG9uZSBsb2NhdGlvbiBpcyBhc3NvY2lhdGVkIHdpdGggdGhlIHZhbHVlcyBvZiB0aGF0IHZhcmlhYmxlIGluIG5lYXJieSBsb2NhdGlvbnMsIHdoZXJlIG5lYXJieSBpcyBhcyBkZWZpbmVkIGJ5IHRoZSB3ZWlnaHRzIG1hdHJpeCBXIChyb29rLCBxdWVlbiwgd2l0aGluIGEgY2VydGFpbiBkaXN0YW5jZSBvZiBvbmUgYW5vdGhlcikuIEluIHNob3J0LCBpdCBpbnRyb2R1Y2VzIGEgc3BhdGlhbGx5IGxhZ2dlZCBkZXBlbmRlbnQgdmFyaWFibGUgaW50byB0aGUgbW9kZWwsIGNvbXBhcmVkIHRvIG91ciBwcmV2aW91cyBPTFMgcmVncmVzc2lvbi4gSW4gb3VyIGNvbnRleHQsIHRoZSBzcGF0aWFsIGxhZyBtb2RlbCBjb3VsZCBiZSByZXByZXNlbnRlZCBhcyB0aGUgZm9sbG93aW5nOiAKCiQkClx0ZXh0e0xOTUVESFZBTH0gPSBccmhvIFcgXGNkb3QgXHRleHR7TE5NRURIVkFMfSArIFxiZXRhXzAgKyBcYmV0YV8xIFxjZG90IFx0ZXh0e1BDVFZBQ0FOVH0gKyBcYmV0YV8yIFxjZG90IFx0ZXh0e1BDVFNJTkdMRVN9ICsgXGJldGFfMyBcY2RvdCBcdGV4dHtQQ1RCQUNITU9SfSArIFxiZXRhXzQgXGNkb3QgXHRleHR7TE5OQkVMUE9WMTAwfSArIFxlcHNpbG9uX2kKJCQKCndoZXJlIFwoXHRleHR7TE5NRURIVkFMfVwpIGlzIHRoZSBsb2cgb2YgbWVkaWFuIGhvbWUgdmFsdWUgaW4gbG9jYXRpb24sIFwoIFxyaG8gXCkgaXMgdGhlIHNwYXRpYWwgbGFnIGNvZWZmaWNpZW50IHRoYXQgbWVhc3VyZXMgdGhlIGluZmx1ZW5jZSBvZiBuZWlnaGJvcmluZyBhcmVhcywgXCggVyBcKSBpcyB0aGUgc3BhdGlhbCB3ZWlnaHRzIG1hdHJpeCAoaW4gdGhpcyBjYXNlLCB0aGUgcXVlZW5saXN0IHNwYXRpYWwgd2VpZ2h0cyksIGFuZCBcKCBXIFxjZG90IFx0ZXh0e0xOTUVESFZBTH0gXCkgaXMgdGhlIHNwYXRpYWxseSBsYWdnZWQgZGVwZW5kZW50IHZhcmlhYmxlLiBUaGUgb3RoZXIgdGVybXMgYXJlIHRoZSBzYW1lIGFzIGluIHRoZSBPTFMgcmVncmVzc2lvbiwgd2hlcmUgXChcdGV4dHtQQ1RWQUNBTlR9XCksIFwoXHRleHR7UENUU0lOR0xFU31cKSwgXChcdGV4dHtQQ1RCQUNITU9SfVwpLCBhbmQgXChcdGV4dHtMTk5CRUxQT1Z9XCkgYXJlIHRoZSBwcmVkaWN0b3JzLCBcKCBcYmV0YV8xLCBcYmV0YV8yLCBcYmV0YV8zLCBcYmV0YV80IFwpIGFyZSB0aGUgY29lZmZpY2llbnRzLCBcKCBcYmV0YV8wIFwpIGlzIHRoZSBpbnRlcmNlcHQgdGVybSwgYW5kIFwoIFxlcHNpbG9uX2kgXCkgaXMgdGhlIGVycm9yIHRlcm0uCgpUaGUgc3BhdGlhbCBlcnJvciBtb2RlbCwgb24gdGhlIG90aGVyIGhhbmQsIGFzc3VtZXMgdGhhdCB0aGUgZXJyb3IgdGVybSBpcyBzcGF0aWFsbHkgYXV0b2NvcnJlbGF0ZWQsIG1lYW5pbmcgdGhhdCB0aGUgcmVzaWR1YWwgaW4gb25lIGxvY2F0aW9uIGlzIGFzc29jaWF0ZWQgd2l0aCByZXNpZHVhbHMgYXQgbmVhcmJ5IGxvY2F0aW9ucywgd2hlcmUgbmVhcmJ5IGlzIGFsc28gZGVpZmluZWQgYnkgdGhlIHdlaWdodCBtYXRyaXguIFRoZSBzcGF0aWFsIGVycm9yIG1vZGVsIGNvdWxkIGJlIHJlcHJlc2VudGVkIGFzIHRoZSBmb2xsb3dpbmc6CgokJApcdGV4dHtMTk1FREhWQUx9ID0gXGJldGFfMCArIFxiZXRhXzEgXGNkb3QgXHRleHR7UENUVkFDQU5UfSArIFxiZXRhXzIgXGNkb3QgXHRleHR7UENUU0lOR0xFU30gKyBcYmV0YV8zIFxjZG90IFx0ZXh0e1BDVEJBQ0hNT1J9ICsgXGJldGFfNCBcY2RvdCBcdGV4dHtMTk5CRUxQT1YxMDB9ICsgXGxhbWJkYSBXIFxjZG90IFxlcHNpbG9uICsgdQokJAoKd2hlcmUgXChcdGV4dHtMTk1FREhWQUx9XCkgaXMgdGhlIGxvZyBvZiBtZWRpYW4gaG9tZSB2YWx1ZSwgXCggXGJldGFfMCBcKSBpcyB0aGUgaW50ZXJjZXB0IHRlcm0sIFwoXHRleHR7UENUVkFDQU5UfVwpLCBcKFx0ZXh0e1BDVFNJTkdMRVN9XCksIFwoXHRleHR7UENUQkFDSE1PUn1cKSwgYW5kIFwoXHRleHR7TE5OQkVMUE9WfVwpIGFyZSB0aGUgcHJlZGljdG9ycywgXCggXGJldGFfMSwgXGJldGFfMiwgXGJldGFfMywgXGJldGFfNCBcKSBhcmUgdGhlIGNvZWZmaWNpZW50cywgYXMgaW4gT0xTIHJlZ3Jlc3Npb24uIFwoIFxsYW1iZGEgXCkgaXMgdGhlIHNwYXRpYWwgZXJyb3IgY29lZmZpY2llbnQgdGhhdCBtZWFzdXJlcyB0aGUgZGVncmVlIG9mIHNwYXRpYWwgY29ycmVsYXRpb24gaW4gdGhlIGVycm9yIHRlcm0sIFwoIFcgXCkgaXMgdGhlIHNwYXRpYWwgd2VpZ2h0cyBtYXRyaXgsIFwoIFcgXGNkb3QgXGVwc2lsb24gXCkgaXMgdGhlIHNwYXRpYWxseSBsYWdnZWQgZXJyb3IgdGVybSwgYW5kIFwoIHUgXCkgaXMgdGhlIHJhbmRvbSBub2lzZS4gVG8gcHV0IGl0IHNpbXBseSwgd2UgYXJlIHJlZ3Jlc3NpbmcgcmVzaWR1YWxzIG9uIHRoZSBuZWFyZXN0IG5laWdoYm9yIHJlc2lkdWFscywgdGhlcmVieSBmaWx0ZXJpbmcgdGhlIHNwYXRpYWwgaW5mb3JtYXRpb24gb3V0IG9mIHRoZSBPTFMgcmVzaWR1YWxzCgpTcGF0aWFsIGVycm9yIHJlZ3Jlc3Npb24gYW5kIHNwYXRpYWwgbGFnIHJlZ3Jlc3Npb24gYm90aCByZXF1aXJlIHRoZSBzdGFuZGFyZCBhc3N1bXB0aW9ucyBmb3IgT0xTIHJlZ3Jlc3Npb27igJRzdWNoIGFzIGxpbmVhcml0eSwgaG9tb3NjZWRhc3RpY2l0eSwgYW5kIG5vcm1hbGl0eSBvZiBlcnJvcnPigJRleGNlcHQgZm9yIHRoZSBhc3N1bXB0aW9uIG9mIHNwYXRpYWwgaW5kZXBlbmRlbmNlIGFtb25nIG9ic2VydmF0aW9ucy4gVGhpcyBhZGp1c3RtZW50IGFsbG93cyB0aGUgbW9kZWwgdG8gYWNjb3VudCBmb3Igc3BhdGlhbCBzdHJ1Y3R1cmUgaW4gZWl0aGVyIHRoZSBkZXBlbmRlbnQgdmFyaWFibGUgKHNwYXRpYWwgbGFnKSBvciB0aGUgZXJyb3IgdGVybSAoc3BhdGlhbCBlcnJvcikuIFRoYXQgc2FpZCwgdGhlaXIgZ29hbCBpcyB0byBhY2NvdW50IGZvciBzcGF0aWFsIGRlcGVuZGVuY2UgaW4gdGhlIGRhdGEsIGFpbWluZyB0byByZWR1Y2Ugc3BhdGlhbCBhdXRvY29ycmVsYXRpb24gaW4gdGhlIHJlZ3Jlc3Npb24gcmVzaWR1YWxzLiBCb3RoIG1ldGhvZHMgbWluaW1pemUgc3BhdGlhbCBwYXR0ZXJucyBpbiByZXNpZHVhbHMgdGhhdCBjb3VsZCBvdGhlcndpc2UgbGVhZCB0byBiaWFzZWQgb3IgaW5lZmZpY2llbnQgZXN0aW1hdGVzLgoKV2UgY29tcGFyZSB0aGUgcmVzdWx0cyBvZiBzcGF0aWFsIGxhZyBhbmQgc3BhdGlhbCBlcnJvciByZWdyZXNzaW9uIHdpdGggT0xTIHRvIGRlY2lkZSB3aGV0aGVyIHRoZSBzcGF0aWFsIG1vZGVscyBwZXJmb3JtIGJldHRlciB0aGFuIE9MUyBiYXNlZCBvbiBhIG51bWJlciBvZiBjcml0ZXJpYTogQWthaWtlIEluZm9ybWF0aW9uIENyaXRlcmlvbiwgU2Nod2FyeiBDcml0ZXJpb24sIExvZyBMaWtlbGlob29kLCBhbmQgTGlrZWxpaG9vZCBSYXRpbyBUZXN0LiBUaGUgKipBa2Fpa2UgSW5mb3JtYXRpb24gQ3JpdGVyaW9uIChBSUMpKiogYW5kICoqU2Nod2FyeiBDcml0ZXJpb24gKFNDIG9yIEJJQykqKiBhcmUgdXNlZCB0byBjb21wYXJlIHRoZSBnb29kbmVzcyBvZiBmaXQgb2YgZGlmZmVyZW50IG1vZGVscy4gVGhleSBhcmUgcmVsYXRpdmUgbWVhc3VyZXMgb2YgdGhlIGluZm9ybWF0aW9uIHRoYXQgaXMgbG9zdCB3aGVuIGEgZ2l2ZW4gbW9kZWwgaXMgdXNlZCB0byBkZXNjcmliZSByZWFsaXR5IGFuZCBjYW4gYmUgc2FpZCB0byBkZXNjcmliZSB0aGUgdHJhZGVvZmYgYmV0d2VlbiBwcmVjaXNpb24gYW5kIGNvbXBsZXhpdHkgb2YgdGhlIG1vZGVsLiBUaGUgbG93ZXIgdGhlIEFJQyBvciBTQywgdGhlIGJldHRlciB0aGUgbW9kZWwuCgpUaGUgKipMb2ctTGlrZWxpaG9vZCoqIGlzIGFzc29jaWF0ZWQgd2l0aCB0aGUgbWF4aW11bSBsaWtlbGlob29kIG1ldGhvZCBvZiBmaXR0aW5nIGEgc3RhdGlzdGljYWwgbW9kZWwgdG8gdGhlIGRhdGEgYW5kIGVzdGltYXRpbmcgbW9kZWwgcGFyYW1ldGVycy4gTWF4aW11bSBsaWtlbGlob29kIHBpY2tzIHRoZSB2YWx1ZXMgb2YgdGhlIG1vZGVsIHBhcmFtZXRlcnMgdGhhdCBtYWtlIHRoZSBkYXRhICJtb3JlIGxpa2VseSIgdGhhbiBhbnkgb3RoZXIgdmFsdWVzIG9mIHRoZSBwYXJhbWV0ZXJzIHdvdWxkIG1ha2UgdGhlbS4gIEhpZ2hlciBsb2ctbGlrZWxpaG9vZCB2YWx1ZXMgaW5kaWNhdGUgYSBtb2RlbCB0aGF0IGJldHRlciBleHBsYWlucyB0aGUgb2JzZXJ2ZWQgZGF0YS4gCgpUaGUgKipMaWtlbGlob29kIFJhdGlvIFRlc3QqKiBpcyB1c2VkIHRvIGZvcm1hbGx5IHRlc3Qgd2hldGhlciBhZGRpbmcgc3BhdGlhbCBkZXBlbmRlbmNlIHRvIGEgbW9kZWwgKGFzIGluIHNwYXRpYWwgbGFnIG9yIHNwYXRpYWwgZXJyb3IgbW9kZWxzKSBzaWduaWZpY2FudGx5IGltcHJvdmVzIG1vZGVsIGZpdCBjb21wYXJlZCB0byBPTFMuIEZvciB0aGlzIHRlc3QsIHRoZSBudWxsIGh5cG90aGVzaXMgKFwoIEhfMCBcKSkgc3RhdGUgdGhhdCB0aGUgc3BhdGlhbCBtb2RlbCBkb2VzIG5vdCBwcm92aWRlIGEgc2lnbmlmaWNhbnRseSBiZXR0ZXIgZml0IHRoYW4gT0xTLCB3aGlsZSB0aGUgYWx0ZXJuYXRpdmUgaHlwb3RoZXNpcyAoXCggSF9hIFwpKSBzdGF0ZXMgdGhhdCB0aGUgc3BhdGlhbCBtb2RlbCBwcm92aWRlcyBhIHNpZ25pZmljYW50bHkgYmV0dGVyIGZpdCB0aGFuIE9MUy4gCgpUaGUgZGVjaXNpb24gcnVsZSBpcyB0byByZWplY3QgdGhlIG51bGwgaHlwb3RoZXNpcyBpZiB0aGUgXCggTFIgXCkgdGVzdCBzdGF0aXN0aWMgaXMgc2lnbmlmaWNhbnQgKGkuZS4sIHRoZSBwLXZhbHVlIGlzIGJlbG93IGEgY2hvc2VuIHNpZ25pZmljYW5jZSBsZXZlbCwgdHlwaWNhbGx5IDAuMDUpLCBhbmQgY29uY2x1ZGUgdGhhdCB0aGUgc3BhdGlhbCBtb2RlbCBpcyBhIGJldHRlciBmaXQgdGhhbiBPTFMuIElmIG5vdCwgT0xTIG1heSBiZSBhZGVxdWF0ZS4gKkl0IHNob3VsZCBiZSBub3RlZCB0aGF0IHRoZSBsb2cgbGlrZWxpaG9vZCBtZXRob2QgYW5kIHRoZSBsaWtlbGlob29kIHJhdGlvIHRlc3Qgc2hvdWxkIGJlIHVzZWQgZm9yIGNvbXBhcmluZyBuZXN0ZWQgbW9kZWxzLiBTcGF0aWFsIGxhZyBhbmQgc3BhdGlhbCBlcnJvciBhcmUgbm90IGEgc3BlY2lhbCBjYXNlIG9mIGVhY2ggb3RoZXIg4oCTIHdlIGNhbm5vdCB1c2UgdGhlIGxvZyBsaWtlbGlob29kIHJhdGlvIHRvIGNvbXBhcmUgdGhlbS4qCgpBbHRlcm5hdGl2ZWx5LCB3ZSBjYW4gYWxzbyBjb21wYXJlIHRoZSBzcGF0aWFsIG1vZGVscyB0byBPTFMgdXNpbmcgdGhlICoqTW9yYW4ncyBJKiogc3RhdGlzdGljLCB3aGljaCBtZWFzdXJlcyB0aGUgc3BhdGlhbCBhdXRvY29ycmVsYXRpb24gb2YgdGhlIHJlc2lkdWFscy4gTW9yYW4ncyBJIHJhbmdlcyBmcm9tIC0xIHRvIDEsIHdoZXJlIC0xIGluZGljYXRlcyBwZXJmZWN0IGRpc3BlcnNpb24sIDAgaW5kaWNhdGVzIG5vIHNwYXRpYWwgYXV0b2NvcnJlbGF0aW9uLCBhbmQgMSBpbmRpY2F0ZXMgcGVyZmVjdCBjb3JyZWxhdGlvbi4gRm9yIG91ciBtb2RlbHMsIHRoZSBnb2FsIGlzIHRvIG1pbmltaXplIHNwYXRpYWwgYXV0b2NvcnJlbGF0aW9uIGluIHRoZSByZXNpZHVhbHMuICBJZiB0aGUgTW9yYW7igJlzIEkgc3RhdGlzdGljIGZvciB0aGUgcmVzaWR1YWxzIG9mIGEgc3BhdGlhbCBsYWcgb3Igc3BhdGlhbCBlcnJvciBtb2RlbCBpcyBjbG9zZXIgdG8gemVybyB0aGFuIHRoZSBNb3JhbuKAmXMgSSBmb3IgdGhlIE9MUyBtb2RlbCwgd2UgY2FuIGNvbmNsdWRlIHRoYXQgdGhlIHNwYXRpYWwgbW9kZWwgYmV0dGVyIGNhcHR1cmVzIHNwYXRpYWwgZGVwZW5kZW5jaWVzLiAKCgojIyBHZW9ncmFwaGljYWxseSBXZWlnaHRlZCBSZWdyZXNzaW9uCgpXZSB3aWxsIGNvbmR1Y3Qgb3VyIEdlb2dyYXBoaWNhbGx5IFdlaWdodGVkIFJlZ3Jlc3Npb24gKEdXUikgYW5hbHlzZXMgaW4gUi4gR1dSIGlzIGEgZm9ybSBvZiBsb2NhbCByZWdyZXNzaW9uIHRoYXQgaGVscHMgYWRkcmVzcyBzcGF0aWFsIGhldGVyb2dlbmVpdHkgaW4gZGF0YSwgd2hpY2ggaXMgZXNzZW50aWFsIHdoZW4gYW5hbHl6aW5nIHNwYXRpYWwgZGF0YSBwcm9uZSB0byBTaW1wc29u4oCZcyBQYXJhZG94IOKAlCB3aGVyZSBhIHRyZW5kIG9ic2VydmVkIGluIGFnZ3JlZ2F0ZSBkYXRhIGNhbiBkaWZmZXIgZnJvbSB0cmVuZHMgaW4gc3Vic2V0cy4gR1dSIGFsbG93cyB1cyB0byBleGFtaW5lIHJlbGF0aW9uc2hpcHMgYXQgYSBsb2NhbCBsZXZlbCByYXRoZXIgdGhhbiBhc3N1bWluZyB0aGV5IGFyZSB1bmlmb3JtIGFjcm9zcyB0aGUgc3R1ZHkgYXJlYS4gVGhlIGdlbmVyYWwgR1dSIGVxdWF0aW9uIGNhbiBiZSBleHByZXNzZWQgYXM6CgoKJCQKeV9pID0gXGJldGFfe2kwfSArIFxzdW1fe2s9MX1ee219IFxiZXRhX3tpa314X3tpa30gKyBcZXBzaWxvbl9pCiQkCgp3aGVyZTogXCggeV9pIFwpIGlzIHRoZSBkZXBlbmRlbnQgdmFyaWFibGUgYXQgbG9jYXRpb24gXChpXCksIFwoIFxiZXRhX3tpMH0gXCkgaXMgdGhlIGludGVyY2VwdCBmb3IgbG9jYXRpb24gXChpXCksIGFsbG93aW5nIGEgdW5pcXVlIGJhc2VsaW5lIGZvciBlYWNoIGxvY2F0aW9uLCBcKCBcYmV0YV97aWt9IFwpIGlzIHRoZSBjb2VmZmljaWVudCBmb3IgdGhlIFwoa1wpLXRoIHByZWRpY3RvciBhdCBsb2NhdGlvbiBcKGlcKSwgXCggeF97aWt9IFwpIGlzIHRoZSB2YWx1ZSBvZiB0aGUgXChrXCktdGggcHJlZGljdG9yIHZhcmlhYmxlIGF0IGxvY2F0aW9uIFwoaVwpLCBhbmQgXCggXGVwc2lsb25faSBcKSBpcyB0aGUgZXJyb3IgdGVybSBhdCBsb2NhdGlvbiBcKGlcKS4KCkluIEdXUiwgbG9jYWwgcmVncmVzc2lvbiBpcyBwZXJmb3JtZWQgYnkgZml0dGluZyBhIHJlZ3Jlc3Npb24gbW9kZWwgYXQgZWFjaCBvYnNlcnZhdGlvbiBwb2ludCwgdXNpbmcgYSBzdWJzZXQgb2YgbmVpZ2hib3JpbmcgcG9pbnRzLCB3aXRoIHdlaWdodHMgYXNzaWduZWQgYmFzZWQgb24gdGhlaXIgZGlzdGFuY2UgZnJvbSB0aGUgZm9jYWwgcG9pbnQuIFRoZSBjb25jZXB0IG9mIGJhbmR3aWR0aCBjb250cm9scyB0aGUgbnVtYmVyIG9mIG5laWdoYm9ycyBpbmNsdWRlZCwgaW5mbHVlbmNpbmcgaG93ICJsb2NhbCIgZWFjaCByZWdyZXNzaW9uIGlzLiBUaGVyZSBhcmUgdHdvIHR5cGVzIG9mIGJhbmR3aWR0aHM6IGFkYXB0aXZlIGFuZCBmaXhlZC4gQSBmaXhlZCBiYW5kd2lkdGggdXNlcyBhIGNvbnN0YW50IGRpc3RhbmNlIGZvciBhbGwgcG9pbnRzLCB3aGlsZSBhbiBhZGFwdGl2ZSBiYW5kd2lkdGggdmFyaWVzLCBhZGp1c3RpbmcgdG8gaW5jbHVkZSBhIHNldCBudW1iZXIgb2YgbmVhcmJ5IG9ic2VydmF0aW9ucyByZWdhcmRsZXNzIG9mIHNwYXRpYWwgZGVuc2l0eS4gSGVyZSwgd2Ugd2lsbCB1c2UgYWRhcHRpdmUgYmFuZHdpZHRoLCB3aGljaCBpcyBtb3JlIGFwcHJvcHJpYXRlIGFzIGl0IGFjY291bnRzIGZvciB2YXJ5aW5nIHNwYXRpYWwgZGVuc2l0aWVzLCBwcm92aWRpbmcgYSBmbGV4aWJsZSBhbmFseXNpcyB0aGF0IGJldHRlciBjYXB0dXJlcyBsb2NhbCByZWxhdGlvbnNoaXBzIGluIGFyZWFzIHdpdGggZGlmZmVyZW50IHBvcHVsYXRpb24gZGlzdHJpYnV0aW9ucy4KCkFsdGhvdWdoIEdXUiBhbGxvd3MgZm9yIHNwYXRpYWwgdmFyaWF0aW9uIGluIHJlbGF0aW9uc2hpcHMsIHRoZSBzdGFuZGFyZCBPTFMgYXNzdW1wdGlvbnMgKGxpbmVhcml0eSwgaW5kZXBlbmRlbmNlLCBob21vc2NlZGFzdGljaXR5LCBhbmQgbm9ybWFsaXR5KSBzdGlsbCBhcHBseS4gTXVsdGljb2xsaW5lYXJpdHkgaXMgYXNzZXNzZWQgdXNpbmcgdGhlIENvbmRpdGlvbiBOdW1iZXIsIGFuZCBoaWdoIG11bHRpY29sbGluZWFyaXR5IGNhbiBjYXVzZSBpc3N1ZXMgaW4gR1dSLCBsZWFkaW5nIHRvIHVuc3RhYmxlIGVzdGltYXRlcyBhbmQgY2x1c3RlcmluZyBpbiBwYXJhbWV0ZXIgZXN0aW1hdGVzLiBJdCBpcyBhbHNvIGltcG9ydGFudCB0byBub3RlIHRoYXQgR1dSIGRvZXMgbm90IHByb3ZpZGUgcC12YWx1ZXMgZm9yIGNvZWZmaWNpZW50cywgYXMgdGhlIG1vZGVsIGZvY3VzZXMgb24gZXhwbG9yaW5nIHNwYXRpYWwgcGF0dGVybnMgcmF0aGVyIHRoYW4gdGVzdGluZyBnbG9iYWwgaHlwb3RoZXNlcy4KCgojIFJlc3VsdHMKCiMjIEdsb2JhbCBhbmQgTG9jYWwgTW9yYW4ncyBJCgpUaGUgR2xvYmFsIE1vcmFuJ3MgSSBhbmFseXNpcyBmb3IgdGhlIGRlcGVuZGVudCB2YXJpYWJsZSwgXChcdGV4dHtMTk1FREhWQUx9XCkgKHRoZSBuYXR1cmFsIGxvZyBvZiBtZWRpYW4gaG91c2UgdmFsdWUpLCByZXZlYWxzIGEgcHJvbm91bmNlZCBsZXZlbCBvZiBzcGF0aWFsIGF1dG9jb3JyZWxhdGlvbi4gV2l0aCBhIE1vcmFuJ3MgSSBzdGF0aXN0aWMgb2YgMC44LCB0aGUgcmVzdWx0cyBpbmRpY2F0ZSBhIHN0cm9uZyBwb3NpdGl2ZSBzcGF0aWFsIGF1dG9jb3JyZWxhdGlvbi4gVGhpcyBoaWdoIHZhbHVlIHN1Z2dlc3RzIHRoYXQgYXJlYXMgd2l0aCBzaW1pbGFyIG1lZGlhbiBob3VzZSB2YWx1ZXMgdGVuZCB0byBjbHVzdGVyIGdlb2dyYXBoaWNhbGx5IHdpdGhpbiB0aGUgc3R1ZHkgYXJlYS4gSW4gb3RoZXIgd29yZHMsIG5laWdoYm9yaG9vZHMgd2l0aCBlaXRoZXIgaGlnaCBvciBsb3cgaG91c2UgdmFsdWVzIGFyZSBtb3JlIGxpa2VseSB0byBiZSBsb2NhdGVkIG5lYXIgb3RoZXIgbmVpZ2hib3Job29kcyB3aXRoIHNpbWlsYXIgdmFsdWVzLCByYXRoZXIgdGhhbiBiZWluZyByYW5kb21seSBkaXN0cmlidXRlZCBhY3Jvc3Mgc3BhY2UuIFRoaXMgc3BhdGlhbCBjbHVzdGVyaW5nIHBvaW50cyB0byB0aGUgcHJlc2VuY2Ugb2Ygc3BhdGlhbCBkZXBlbmRlbmNpZXMgaW4gaG91c2luZyB2YWx1ZXMsIHBvc3NpYmx5IGRyaXZlbiBieSBuZWlnaGJvcmhvb2QgY2hhcmFjdGVyaXN0aWNzLCBzb2Npby1lY29ub21pYyBmYWN0b3JzLCBvciBvdGhlciBzcGF0aWFsIHByb2Nlc3NlcyBpbmZsdWVuY2luZyBwcm9wZXJ0eSB2YWx1ZXMgYWNyb3NzIHRoZSByZWdpb24uCgpUbyB2YWxpZGF0ZSB0aGUgc2lnbmlmaWNhbmNlIG9mIHRoaXMgb2JzZXJ2ZWQgc3BhdGlhbCBhdXRvY29ycmVsYXRpb24sIGEgTW9udGUgQ2FybG8gcGVybXV0YXRpb24gdGVzdCB3YXMgY29uZHVjdGVkIHVzaW5nIDEwMDAgc2ltdWxhdGlvbnMuIFRoaXMgYXBwcm9hY2ggaW52b2x2ZWQgcmFuZG9tbHkgcGVybXV0aW5nIHRoZSB2YWx1ZXMgb2YgXChcdGV4dHtMTk1FREhWQUx9XCkgYWNyb3NzIHNwYXRpYWwgdW5pdHMgdG8gZ2VuZXJhdGUgYSBkaXN0cmlidXRpb24gb2YgTW9yYW4ncyBJIHZhbHVlcyB1bmRlciB0aGUgbnVsbCBoeXBvdGhlc2lzIG9mIG5vIHNwYXRpYWwgYXV0b2NvcnJlbGF0aW9uLiBUaGUgcmVzdWx0cywgdmlzdWFsaXplZCBpbiBhIGhpc3RvZ3JhbSBvZiBwZXJtdXRlZCBNb3JhbuKAmXMgSSB2YWx1ZXMsIHNob3cgdGhhdCB0aGUgb2JzZXJ2ZWQgTW9yYW7igJlzIEkgb2YgMC44IGxpZXMgYXQgdGhlIGV4dHJlbWUgZW5kIG9mIHRoaXMgZGlzdHJpYnV0aW9uLCBtYXJrZWQgaW4gcmVkLiBXaXRoIGFuIG9ic2VydmVkIHJhbmsgb2YgMTAwMCAodGhlIGhpZ2hlc3QgcmFuayBpbiB0aGUgZGlzdHJpYnV0aW9uKSwgdGhlIG9ic2VydmVkIE1vcmFu4oCZcyBJIHZhbHVlIGV4Y2VlZGVkIGFsbCBwZXJtdXRlZCB2YWx1ZXMsIGVtcGhhc2l6aW5nIHRoZSBleHRyZW1pdHkgb2YgdGhlIHNwYXRpYWwgY2x1c3RlcmluZyBpbiB0aGUgYWN0dWFsIGRhdGEuCgpUaGUgdGVzdCByZXN1bHQgaXMgZnVydGhlciBzdXBwb3J0ZWQgYnkgYSBoaWdobHkgc2lnbmlmaWNhbnQgcC12YWx1ZSAoXCggcCA8IDIgXHRpbWVzIDEwXnstMTZ9IFwpKS4gVGhpcyBleGNlcHRpb25hbGx5IGxvdyBwLXZhbHVlIHN0cm9uZ2x5IHJlamVjdHMgdGhlIG51bGwgaHlwb3RoZXNpcyBvZiBubyBzcGF0aWFsIGF1dG9jb3JyZWxhdGlvbiwgY29uZmlybWluZyB0aGF0IHRoZSBzcGF0aWFsIGFycmFuZ2VtZW50IG9mIFwoXHRleHR7TE5NRURIVkFMfVwpIHZhbHVlcyBpcyBub3QgcmFuZG9tLiBJbnN0ZWFkLCB0aGUgb2JzZXJ2ZWQgY2x1c3RlcmluZyBpcyBzdGF0aXN0aWNhbGx5IHNpZ25pZmljYW50LCBpbmRpY2F0aW5nIHRoYXQgc3BhdGlhbCBwcm9jZXNzZXMgYXJlIGxpa2VseSBpbmZsdWVuY2luZyB0aGUgZGlzdHJpYnV0aW9uIG9mIGhvdXNpbmcgdmFsdWVzIGluIHRoZSBzdHVkeSBhcmVhLgoKYGBge3IgY29uc3RydWN0IHF1ZWVuIG5laWdoYm9ycywgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgaW5jbHVkZT1GQUxTRX0KCnF1ZWVuPC1wb2x5Mm5iKHJlZ0RhdGEsIHJvdy5uYW1lcz1yZWdEYXRhJFBPTFlfSUQpCnF1ZWVubGlzdDwtbmIybGlzdHcocXVlZW4sIHN0eWxlID0gJ1cnKQoKYGBgCgoKYGBge3IgZ2xvYmFsIG1vcmFuIEksIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CgpnbG9iYWxtb3Jhbk1DPC1tb3Jhbi5tYyhyZWdEYXRhJExOTUVESFZBTCwgcXVlZW5saXN0LCBuc2ltPTk5OSwgYWx0ZXJuYXRpdmU9InR3by5zaWRlZCIpIApnbG9iYWxtb3Jhbk1DCgpgYGAKClRoaXMgZ3JhcGggc2hvd3MgdGhlIHJlc3VsdHMgb2YgdGhlIE1vbnRlIENhcmxvIHBlcm11dGF0aW9uIHRlc3QgdG8gYXNzZXNzIHRoZSBzaWduaWZpY2FuY2Ugb2YgdGhlIG9ic2VydmVkIE1vcmFu4oCZcyBJIHN0YXRpc3RpYy5UaGUgaGlzdG9ncmFtIHNob3dzIHRoZSBmcmVxdWVuY3kgb2YgTW9yYW4ncyBJIHZhbHVlcyBnZW5lcmF0ZWQgYnkgdGhlc2UgcmFuZG9tIHBlcm11dGF0aW9ucywgd2l0aCB0aGUgb2JzZXJ2ZWQgTW9yYW7igJlzIEkgdmFsdWUgaGlnaGxpZ2h0ZWQgaW4gcmVkLiBUaGUgb2JzZXJ2ZWQgc3RhdGlzdGljIG9mIDAuOCBzdGFuZHMgZmFyIHRvIHRoZSByaWdodCBvZiB0aGUgcGVybXV0ZWQgdmFsdWVzLCB1bmRlcnNjb3JpbmcgaXRzIGV4dHJlbWl0eSBhbmQgc2lnbmlmaWNhbmNlLiBUaGUgaGlnaCBvYnNlcnZlZCByYW5rICgxMDAwKSBpbmRpY2F0ZXMgdGhhdCBub25lIG9mIHRoZSBwZXJtdXRlZCB2YWx1ZXMgZXhjZWVkZWQgdGhlIGFjdHVhbCBNb3JhbuKAmXMgSS4gVGhpcyBleHRyZW1lbHkgbG93IHAtdmFsdWUgcHJvdmlkZXMgc3Ryb25nIGV2aWRlbmNlIGFnYWluc3QgdGhlIG51bGwgaHlwb3RoZXNpcyBvZiBubyBzcGF0aWFsIGF1dG9jb3JyZWxhdGlvbiwgY29uZmlybWluZyB0aGF0IHRoZSBzcGF0aWFsIGNsdXN0ZXJpbmcgb2JzZXJ2ZWQgaW4gXChcdGV4dHtMTk1FREhWQUx9XCkgaXMgc3RhdGlzdGljYWxseSBzaWduaWZpY2FudCBhbmQgdW5saWtlbHkgdG8gYmUgZHVlIHRvIHJhbmRvbSB2YXJpYXRpb24uCgpgYGB7ciBnbG9iYWwgbW9yYW4gaGlzdG9ncmFtIHBsb3QsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CgpnZ3Bsb3QoZGF0YS5mcmFtZShyZXMgPSBnbG9iYWxtb3Jhbk1DJHJlcyksIGFlcyh4ID0gcmVzKSkgKwogIGdlb21faGlzdG9ncmFtKGJpbnMgPSAxMDAsIGZpbGwgPSAiIzI4M2QzYiIpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBnbG9iYWxtb3Jhbk1DJHN0YXRpc3RpYywgY29sb3IgPSAiI2M0NDUzNiIsIGxpbmV0eXBlID0gJ2Rhc2hlZCcsIHNpemUgPSAxKSArCiAgbGFicyh0aXRsZSA9ICJPYnNlcnZlZCBhbmQgUGVybXV0ZWQgR2xvYmFsIE1vcmFuJ3MgSSIsCiAgICAgICBzdWJ0aXRsZSA9ICJPYnNlcnZlZCBNb3JhbidzIEkgaW4gUmVkIiwKICAgICAgIHggPSAiTW9yYW4ncyBJIiwKICAgICAgIHkgPSAiQ291bnQiKSArCiAgdGhlbWVfbGlnaHQoKSArICAgCiAgdGhlbWUocGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gOSxmYWNlID0gIml0YWxpYyIpLAogICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyLCBmYWNlID0gImJvbGQiKSwgCiAgICAgICAgYXhpcy50ZXh0Lng9ZWxlbWVudF90ZXh0KHNpemU9NiksCiAgICAgICAgYXhpcy50ZXh0Lnk9ZWxlbWVudF90ZXh0KHNpemU9NiksIAogICAgICAgIGF4aXMudGl0bGU9ZWxlbWVudF90ZXh0KHNpemU9OCkpCgpgYGAKClRoaXMgZ3JhcGggb2ZmZXJzIGEgZGlmZmVyZW50IHBlcnNwZWN0aXZlIG9uIHRoZSBzcGF0aWFsIHN0cnVjdHVyZSBvZiBcKFx0ZXh0e0xOTUVESFZBTH1cKSBieSBkaXNwbGF5aW5nIGEgc2NhdHRlciBwbG90IG9mIHRoZSB2YXJpYWJsZeKAmXMgdmFsdWVzIGFnYWluc3QgdGhlaXIgc3BhdGlhbCBsYWcgKGEgbWVhc3VyZSBvZiBuZWlnaGJvcmluZyB2YWx1ZXMpLiBUaGUgeC1heGlzIHJlcHJlc2VudHMgdGhlIGxvZ2dlZCBtZWRpYW4gaG91c2UgdmFsdWVzIFwoXHRleHR7TE5NRURIVkFMfVwpLCB3aGlsZSB0aGUgeS1heGlzIGRpc3BsYXlzIHRoZSBzcGF0aWFsbHkgbGFnZ2VkIHZhbHVlcyBvZiAgXChcdGV4dHtMTk1FREhWQUx9XCksIGNvbXB1dGVkIGJhc2VkIG9uIGEgcXVlZW4gY29udGlndWl0eSBzcGF0aWFsIHdlaWdodHMgbWF0cml4IHRoYXQgY29uc2lkZXJzIG5laWdoYm9yaW5nIHNwYXRpYWwgdW5pdHMuIFRoZSBwb3NpdGl2ZSBzbG9wZSBvZiB0aGUgcmVkIHRyZW5kIGxpbmUgaW4gdGhlIHNjYXR0ZXIgcGxvdCBpbmRpY2F0ZXMgYSBwb3NpdGl2ZSBzcGF0aWFsIGF1dG9jb3JyZWxhdGlvbiwgd2hlcmUgYXJlYXMgd2l0aCBoaWdoZXIgbWVkaWFuIGhvdXNlIHZhbHVlcyBhcmUgdHlwaWNhbGx5IHN1cnJvdW5kZWQgYnkgb3RoZXIgYXJlYXMgd2l0aCBoaWdoIHZhbHVlcywgYW5kIHNpbWlsYXJseSwgYXJlYXMgd2l0aCBsb3dlciB2YWx1ZXMgYXJlIG5lYXIgb3RoZXIgbG93LXZhbHVlIGFyZWFzLiBUaGlzIGxpbmVhciByZWxhdGlvbnNoaXAgYmV0d2VlbiBhIGxvY2F0aW9u4oCZcyBcKFx0ZXh0e0xOTUVESFZBTH1cKSBhbmQgdGhlIGF2ZXJhZ2UgdmFsdWVzIGluIHN1cnJvdW5kaW5nIGxvY2F0aW9ucyBoaWdobGlnaHRzIHRoZSBjbHVzdGVyaW5nIG9mIHNpbWlsYXIgdmFsdWVzIGFuZCBzdXBwb3J0cyB0aGUgcmVzdWx0IGZyb20gdGhlIEdsb2JhbCBNb3JhbuKAmXMgSSBzdGF0aXN0aWMuCgpgYGB7ciBnbG9iYWwgbW9yYW4gc2NhdHRlciBwbG90LCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQoKZ2dwbG90KGRhdGEgPSBkYXRhLmZyYW1lKAogIExOTUVESFZBTCA9IHJlZ0RhdGEkTE5NRURIVkFMLAogIHNwYXRpYWxfbGFnID0gbGFnLmxpc3R3KHF1ZWVubGlzdCwgcmVnRGF0YSRMTk1FREhWQUwpCiksIGFlcyh4ID0gTE5NRURIVkFMLCB5ID0gc3BhdGlhbF9sYWcpKSArCiAgZ2VvbV9wb2ludChjb2xvciA9ICIjMjgzZDNiIiwgYWxwaGEgPSAwLjcsIHNpemUgPSAwLjYpICsgIAogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIGNvbG9yID0gIiNjNDQ1MzYiLCBzZSA9IEZBTFNFKSArIAogIGxhYnModGl0bGUgPSAiR2xvYmFsIE1vcmFuJ3MgSSBTY2F0dGVyIFBsb3QiLAogICAgICAgeCA9ICJMb2dnZWQgTWVkaWFuIEhvdXNlIFZhbHVlIiwKICAgICAgIHkgPSAiU3BhdGlhbCBMYWcgb2YgTE5NRURIVkFMIikgKwogIHRoZW1lX2xpZ2h0KCkgKyAgIAogIHRoZW1lKHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDksZmFjZSA9ICJpdGFsaWMiKSwKICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiwgZmFjZSA9ICJib2xkIiksIAogICAgICAgIGF4aXMudGV4dC54PWVsZW1lbnRfdGV4dChzaXplPTYpLAogICAgICAgIGF4aXMudGV4dC55PWVsZW1lbnRfdGV4dChzaXplPTYpLCAKICAgICAgICBheGlzLnRpdGxlPWVsZW1lbnRfdGV4dChzaXplPTgpKQoKYGBgCgoKYGBge3IgY29tcHV0ZSBsb2NhbCBtb3JhbiBJLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBpbmNsdWRlPUZBTFNFfQoKbG9jYWxtb3JhbiA8LWxvY2FsbW9yYW4ocmVnRGF0YSRMTk1FREhWQUwgLCBxdWVlbmxpc3QpCmxvY2FsbW9yYW4gPC1jYmluZChyZWdEYXRhLCBhcy5kYXRhLmZyYW1lKGxvY2FsbW9yYW4pKQoKYGBgCgpJbiBhIExvY2FsIE1vcmFuJ3MgSSBzaWduaWZpY2FuY2UgbWFwLCBhcmVhcyB3aXRoIHNpZ25pZmljYW50IGxvdyBwLXZhbHVlcyByZWZlcnMgdG8gYXJlYSB3aGVyZSB0aGUgc3BhdGlhbCBhdXRvY29ycmVsYXRpb24gaXMgc3RhdGlzdGljYWxseSBzaWduaWZpY2FudCwgZWl0aGVyIGhvdHNwb3RzIG9mIGNvbmNlbnRyYXRlZCBoaWdoIHZhbHVlcyBvciBjb2xkIHNwb3RzIG9mIGxvdyB2YWx1ZXMuIFRoZXJlIGFyZWFzIGFyZSBtb3N0bHkgZm91bmQgaW4gdGhlIG5vcnRod2VzdGVybiBhbmQgY2VudHJhbCBwYXJ0cyBvZiB0aGUgY2l0eS4gQXMgd2UgbWF5IHNlZSwgdGhlc2UgYXJlYXMgYXJlIHRoZW4gc3Vycm91bmRlZCBieSBhcmVhcyB3aXRoIHNsaWdodGx5IGhpZ2hlciBwLXZhbHVlcyBhbmQgdGhlbiBhcmVhcyB3aXRoIGV2ZW4gaGlnaGVyIHAtdmFsdWVzLCB1bnRpbCBwIGJlY29tZXMgaW5zaWduaWZpY2FudC4gCgpgYGB7ciBsb2NhbCBtb3JhbiBzaWduaWZpY2FuY2UgbWFwLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQoKbW9yYW5TaWcucGxvdCA8LSBmdW5jdGlvbihkZiwgbGlzdHcsIHRpdGxlKSB7CiAgCiAgbG9jYWwgPC0gbG9jYWxtb3Jhbih4ID0gZGYkTE5NRURIVkFMLCBsaXN0dyA9IGxpc3R3LCB6ZXJvLnBvbGljeSA9IEZBTFNFKQogIAogIGRmJFByLnogPC0gbG9jYWxbLCAgIlByKHogIT0gRShJaSkpIl0gIAogIAogIGRmJHB2YWxfY2F0ZWdvcnkgPC0gY3V0KGRmJFByLnosIAogICAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IGMoMCwgMC4wMDEsIDAuMDEsIDAuMDUsIDEpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCIwLjAwMCAtIDAuMDAxIiwgIjAuMDAxIC0gMC4wMTAiLCAiMC4wMTAgLSAwLjA1MCIsICIwLjA1MCAtIDEuMDAwIiksIAogICAgICAgICAgICAgICAgICAgICAgICAgIGluY2x1ZGUubG93ZXN0ID0gVFJVRSkKICAKICBpZiAoIWluaGVyaXRzKGRmLCAic2YiKSkgewogICAgZGYgPC0gc3RfYXNfc2YoZGYpCiAgfQogIAogIGdncGxvdChkYXRhID0gZGYpICsKICAgIGdlb21fc2YoYWVzKGZpbGwgPSBwdmFsX2NhdGVnb3J5KSwgY29sb3IgPSBOQSwgYWxwaGEgPSAwLjkpICsKICAgIHNjYWxlX2ZpbGxfYnJld2VyKHR5cGUgPSAiZGl2IiwgcGFsZXR0ZSA9IDYsIG5hbWUgPSAiUC1WYWx1ZSIpICsKICAgIGxhYnModGl0bGUgPSB0aXRsZSkgKwogICAgdGhlbWUobGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDkpLAogICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApLAogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGlja3MueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRpY2tzLnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgcGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gOSwgZmFjZSA9ICJpdGFsaWMiKSwKICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiwgZmFjZSA9ICJib2xkIiksCiAgICAgICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gImdyZXkiLCBmaWxsID0gTkEsIHNpemUgPSAwLjgpKQp9Cgptb3JhblNpZy5wbG90KGxvY2FsbW9yYW4sIHF1ZWVubGlzdCwgJ1NpZ25pZmljYW5jZSBNYXAgb2YgTG9jYWwgTW9yYW4gSScpCgpgYGAKClRoZSBDbHVzdGVyIE1hcCBkZXJpdmVkIGZyb20gdGhlIExvY2FsIE1vcmFu4oCZcyBJIGFuYWx5c2lzIGNsYXNzaWZpZWQgY2Vuc3VzIHRyYWN0cyBpbiBQaGlsYWRlbHBoaWEgaW50byAgaGlnaC1oaWdoLCBoaWdoLWxvdywgbG93LWhpZ2gsIGxvdy1sb3csIG9yIG5vdCBzaWduaWZpY2FudCwgcmVwcmVzZW50aW5nIGRpZmZlcmVudCB0eXBlcyBvZiBzcGF0aWFsIHJlbGF0aW9uc2hpcHMgaW4gaG91c2UgdmFsdWVzIHdpdGhpbiBuZWlnaGJvcmhvb2RzIGFuZCB0aGVpciBzdXJyb3VuZGluZ3MuCgoqKkhpZ2gtSGlnaCBDbHVzdGVycyoqOiBBcmVhcyBjbGFzc2lmaWVkIGFzIGhpZ2gtaGlnaCBhcmUgdGhvc2Ugd2hlcmUgaGlnaCB2YWx1ZXMgb2YgbWVkaWFuIGhvdXNlIHByaWNlcyBhcmUgc3Vycm91bmRlZCBieSBvdGhlciBoaWdoLXZhbHVlIGFyZWFzLiBUaGVzZSBjbHVzdGVycyBhcmUgcHJvbWluZW50bHkgbG9jYXRlZCBpbiB0aGUgbm9ydGh3ZXN0ZXJuIHBhcnRzIG9mIHRoZSBjaXR5IGFuZCBzb21lIGNlbnRyYWwgcmVnaW9ucywgaW5kaWNhdGluZyBwb2NrZXRzIG9mIGVjb25vbWljIGFmZmx1ZW5jZS4gVGhlIGhpZ2ggY29uY2VudHJhdGlvbiBvZiBoaWdoLXZhbHVlIHByb3BlcnRpZXMgaW4gdGhlc2UgcmVnaW9ucyBzdWdnZXN0cyBlc3RhYmxpc2hlZCwgYWZmbHVlbnQgbmVpZ2hib3Job29kcyB3aGVyZSBob3VzaW5nIHByaWNlcyByZW1haW4gaGlnaCBkdWUgdG8gZGVtYW5kIGFuZCBwb3NzaWJseSB0aGUgcHJlc2VuY2Ugb2YgYW1lbml0aWVzIG9yIG90aGVyIGF0dHJhY3RpdmUgdXJiYW4gZmVhdHVyZXMuCgoqKkxvdy1Mb3cgQ2x1c3RlcnMqKjogTG93LWxvdyBjbHVzdGVycyByZXByZXNlbnQgYXJlYXMgd2hlcmUgbG93IHByb3BlcnR5IHZhbHVlcyBhcmUgc3Vycm91bmRlZCBieSBvdGhlciBsb3ctdmFsdWUgYXJlYXMsIGhpZ2hsaWdodGluZyBlY29ub21pY2FsbHkgZGlzYWR2YW50YWdlZCB6b25lcy4gVGhlc2UgY2x1c3RlcnMgYXJlIHByZWRvbWluYW50bHkgZm91bmQgaW4gdGhlIHNvdXRod2VzdGVybiBhbmQgbm9ydGhlYXN0ZXJuIHBhcnRzIG9mIHRoZSBjaXR5LiBUaGUgc3BhdGlhbCBjbHVzdGVyaW5nIG9mIGxvdy12YWx1ZSBwcm9wZXJ0aWVzIGluIHRoZXNlIGFyZWFzIHN1Z2dlc3RzIG5laWdoYm9yaG9vZHMgdGhhdCBtYXkgZmFjZSBlY29ub21pYyBjaGFsbGVuZ2VzLCBwb3NzaWJseSB3aXRoIGxpbWl0ZWQgYWNjZXNzIHRvIGFtZW5pdGllcyBvciBmZXdlciBpbnZlc3RtZW50IG9wcG9ydHVuaXRpZXMuIFRoZXNlIHJlZ2lvbnMgbWF5IHJlcXVpcmUgdGFyZ2V0ZWQgcG9saWN5IGludGVydmVudGlvbnMgdG8gYWRkcmVzcyB1bmRlcmx5aW5nIGlzc3VlcyB0aGF0IGNvbnRyaWJ1dGUgdG8gdGhlIGxvd2VyIHByb3BlcnR5IHZhbHVlcy4KCioqSGlnaC1Mb3cgQ2x1c3RlcnMqKjogSGlnaC1sb3cgY2x1c3RlcnMgYXJlIHRyYW5zaXRpb25hbCB6b25lcyB3aGVyZSBoaWdoLXZhbHVlIGFyZWFzIGFyZSBhZGphY2VudCB0byBsb3dlci12YWx1ZSBhcmVhcy4gVGhlc2UgYXJlYXMsIG1hcmtlZCBpbiBsaWdodCByZWQgb24gdGhlIG1hcCwgYXJlIGdlbmVyYWxseSBzY2F0dGVyZWQgYXJvdW5kIHRoZSBib3VuZGFyaWVzIG9mIGhpZ2gtdmFsdWUgbmVpZ2hib3Job29kcywgc3VjaCBhcyBpbiBzZWN0aW9ucyBvZiBjZW50cmFsIGFuZCBub3J0aHdlc3QgUGhpbGFkZWxwaGlhLiBUaGUgcHJveGltaXR5IG9mIGhpZ2gtdmFsdWUgcHJvcGVydGllcyB0byBsb3dlci12YWx1ZSBvbmVzIGluIHRoZXNlIGNsdXN0ZXJzIGNhbiBpbmRpY2F0ZSBlY29ub21pYyBjb250cmFzdHMgb3IgYXJlYXMgZXhwZXJpZW5jaW5nIGdlbnRyaWZpY2F0aW9uLCB3aGVyZSBwcm9wZXJ0eSB2YWx1ZXMgaW4gdHJhZGl0aW9uYWxseSBsb3dlci1pbmNvbWUgbmVpZ2hib3Job29kcyBtYXkgYmUgaW5jcmVhc2luZyBkdWUgdG8gc3BpbGxvdmVyIGVmZmVjdHMgZnJvbSBuZWFyYnkgYWZmbHVlbnQgYXJlYXMuCgoqKkxvdy1IaWdoIENsdXN0ZXJzKio6IExvdy1oaWdoIGNsdXN0ZXJzLCB3aGVyZSBsb3ctdmFsdWUgcHJvcGVydGllcyBhcmUgc3Vycm91bmRlZCBieSBoaWdoZXItdmFsdWUgYXJlYXMsIGFyZSBsZXNzIGNvbW1vbiBidXQgYXBwZWFyIGluIHRoZSBub3J0aGVybiBhbmQgZWFzdGVybiBwYXJ0cyBvZiB0aGUgY2l0eS4gVGhlc2UgY2x1c3RlcnMgc3VnZ2VzdCBpc29sYXRlZCBwb2NrZXRzIG9mIGVjb25vbWljIGRpc2FkdmFudGFnZSB3aXRoaW4gbW9yZSBhZmZsdWVudCBhcmVhcy4gVGhpcyBwYXR0ZXJuIG1heSBpbmRpY2F0ZSBhcmVhcyB0aGF0IGFyZSB5ZXQgdG8gYmVuZWZpdCBmcm9tIHN1cnJvdW5kaW5nIGVjb25vbWljIGdyb3d0aCBvciBtaWdodCBiZSBleHBlcmllbmNpbmcgY2hhbGxlbmdlcyB0aGF0IHByZXZlbnQgdGhlbSBmcm9tIGFsaWduaW5nIHdpdGggdGhlIHByb3NwZXJpdHkgb2YgbmVpZ2hib3JpbmcgcmVnaW9ucy4KCioqTm90IFNpZ25pZmljYW50IEFyZWFzKio6IExhc3RseSwgdGhlIG5vdCBzaWduaWZpY2FudCBhcmVhcywgc2hhZGVkIGluIGdyYXksIGluZGljYXRlIG5laWdoYm9yaG9vZHMgd2hlcmUgdGhlIGxvY2FsIE1vcmFu4oCZcyBJIHN0YXRpc3RpYyB3YXMgbm90IHNpZ25pZmljYW50LiBUaGVzZSByZWdpb25zIGFyZSBzY2F0dGVyZWQgdGhyb3VnaG91dCB0aGUgY2l0eSwgcmVwcmVzZW50aW5nIGFyZWFzIHdoZXJlIGhvdXNlIHZhbHVlcyBkbyBub3QgZXhoaWJpdCBzdHJvbmcgc3BhdGlhbCBjbHVzdGVyaW5nLiBUaGUgbGFjayBvZiBzaWduaWZpY2FudCBjbHVzdGVyaW5nIGluIHRoZXNlIGFyZWFzIHN1Z2dlc3RzIGEgbW9yZSByYW5kb20gZGlzdHJpYnV0aW9uIG9mIGhvdXNlIHZhbHVlcywgd2hpY2ggbWF5IG9jY3VyIGluIG1vcmUgbWl4ZWQtdXNlIG9yIHRyYW5zaXRpb25hbCBuZWlnaGJvcmhvb2RzIHdoZXJlIGVjb25vbWljIGNoYXJhY3RlcmlzdGljcyBhcmUgdmFyaWVkLgoKCmBgYHtyIGxvY2FsIG1vcmFuIGNsdXN0ZXIgbWFwLG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmhsLnBsb3QgPC0gZnVuY3Rpb24oZGYsIGxpc3R3KSB7CgogIGxvY2FsIDwtIGxvY2FsbW9yYW4oeCA9IGRmJExOTUVESFZBTCwgbGlzdHcgPSBsaXN0dywgemVyby5wb2xpY3kgPSBGQUxTRSkKICBxdWFkcmFudCA8LSB2ZWN0b3IobW9kZSA9ICdudW1lcmljJywgbGVuZ3RoID0gbnJvdyhkZikpICAKICAKICBtLnByb3AgPC0gZGYkTE5NRURIVkFMIC0gbWVhbihkZiRMTk1FREhWQUwpCiAgbS5sb2NhbCA8LSBsb2NhbFssIDFdIC0gbWVhbihsb2NhbFssIDFdKQogIHNpZ25pZiA8LSAwLjA1CiAgCiAgcXVhZHJhbnRbbS5wcm9wID4gMCAmIG0ubG9jYWwgPiAwXSA8LSAxICAjIGhpZ2gtaGlnaAogIHF1YWRyYW50W20ucHJvcCA8IDAgJiBtLmxvY2FsIDwgMF0gPC0gMiAgIyBsb3ctbG93CiAgcXVhZHJhbnRbbS5wcm9wIDwgMCAmIG0ubG9jYWwgPiAwXSA8LSA0ICAjIGxvdy1oaWdoCiAgcXVhZHJhbnRbbS5wcm9wID4gMCAmIG0ubG9jYWwgPCAwXSA8LSAzICAjIGhpZ2gtbG93CiAgcXVhZHJhbnRbbG9jYWxbLCA1XSA+IHNpZ25pZl0gPC0gNSAgIyBpbnNpZ25pZmljYW50CiAgCiAgZGYkcXVhZHJhbnQgPC0gZmFjdG9yKHF1YWRyYW50LCBsZXZlbHMgPSBjKDEsIDMsIDUsIDIsIDQpLCAKICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygiSGlnaC1IaWdoIiwgIkhpZ2gtTG93IiwgIk5vbi1TaWduaWZpY2FudCIsICJMb3ctTG93IiwgIkxvdy1IaWdoIikpCiAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgaWYgKCFpbmhlcml0cyhkZiwgInNmIikpIHsKICAgIGRmIDwtIHN0X2FzX3NmKGRmKQogIH0KICAKICBnZ3Bsb3QoZGF0YSA9IGRmKSArCiAgICBnZW9tX3NmKGFlcyhmaWxsID0gcXVhZHJhbnQpLCBjb2xvciA9ICIjODQ4ODg0IiwgbHdkID0gMC4wNykgKwogICAgc2NhbGVfZmlsbF9icmV3ZXIodHlwZSA9ICJkaXYiLCBwYWxldHRlID0gNiwgbmFtZSA9ICJDbHVzdGVyIFR5cGUiKSArIAogICAgbGFicyh0aXRsZSA9ICJMb2NhbCBNb3JhbidzIEkgQ2x1c3RlciBNYXAiKSArCiAgICB0aGVtZShsZWdlbmQucG9zaXRpb249InJpZ2h0IiwKICAgICAgICBheGlzLnRleHQueD1lbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50ZXh0Lnk9ZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGlja3MgPWVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDksZmFjZSA9ICJpdGFsaWMiKSwKICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiwgZmFjZSA9ICJib2xkIiksCiAgICAgICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gImdyZXkiLCBmaWxsPU5BLCBsaW5ld2lkdGg9MC44KQogICAgICAgICkKfQoKaGwucGxvdChyZWdEYXRhLCBxdWVlbmxpc3QpCgpgYGAKCiMjIE9MUyBSZWdyZXNzaW9uIFJlc3VsdHMKCkJlbG93LCB3ZSB3aWxsIHByb3ZpZGUgYSBxdWljayB3YWxrIHRocm91Z2ggb2YgdGhlIE9MUyByZWdyZXNzaW9uIHJlc3VsdHMuIERldGFpbCBpbnRlcnByZXRhdGlvbiBhbmQgZGljdXNzaW9uIG9mIHRoZSByZXN1bHRzIGNhbiBiZSBmb3VuZCBpbiB0aGUgW0dpdEh1YiByZXBvc2l0b3J5XShodHRwczovL2dpdGh1Yi5jb20vZW1pbHl6aG91MTEyL0NQTE42NzEtT0xTLVJlZ3Jlc3Npb24pIGZvciBhc3NpZ25tZW50IDEuCgpBbGwgcHJlZGljdG9ycyBpbiBvdXIgT0xTIHJlZ3Jlc3Npb24sIHdoaWNoIGluY2x1ZGUgXChcdGV4dHtQQ1RTSU5HTEVTfVwpLCBcKFx0ZXh0e1BDVFZBQ0FOVH1cKSwgXChcdGV4dHtMTk5CRUxQT1Z9XCksIGFuZCBcKFx0ZXh0e1BDVEJBQ0hNT1J9XCksIGFyZSBzdGF0aXN0aWNhbGx5IHNpZ25pZmljYW50IGluIGV4cGxhaW5pbmcgXChcdGV4dHtMTk1FREhWQUx9XCkuIFRoZSBtb2RlbCBhY2NvdW50cyBmb3IgYXBwcm94aW1hdGVseSA2Ni4yJSBvZiB0aGUgdmFyaWFuY2UsIGFzIGluZGljYXRlZCBieSB0aGUgUi1zcXVhcmVkIHZhbHVlIG9mIDAuNjYyLgoKCmBgYHtyIG9scyByZWdyZXNzaW9uLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQoKT0xTIDwtIGxtKExOTUVESFZBTCB+IFBDVFZBQ0FOVCArIFBDVFNJTkdMRVMgKyBQQ1RCQUNITU9SICsgTE5OQkVMUE9WLCBkYXRhPXJlZ0RhdGEpCmZpdHRlZF92YWx1ZXMgPC0gZml0dGVkKE9MUykKcmVzaWR1YWxzX3ZhbHVlcyA8LSByZXNpZHVhbHMoT0xTKQpzdGFuZGFyZGl6ZWRfcmVzaWR1YWxzIDwtIHJzdGFuZGFyZChPTFMpCnJlc25iPC1zYXBwbHkocXVlZW4sIGZ1bmN0aW9uKHgpIG1lYW4oc3RhbmRhcmRpemVkX3Jlc2lkdWFsc1t4XSkpCnJlZ0RhdGEgPC0gcmVnRGF0YSAlPiUKICBtdXRhdGUoCiAgICBGaXR0ZWQgPSBmaXR0ZWRfdmFsdWVzLAogICAgUmVzaWR1YWxzID0gcmVzaWR1YWxzX3ZhbHVlcywKICAgIFN0YW5kYXJkaXplZF9SZXNpZHVhbHMgPSBzdGFuZGFyZGl6ZWRfcmVzaWR1YWxzLAogICAgUmVzaWR1YWxzX05CID0gcmVzbmIpCgpzdW1tYXJ5KE9MUykKCmBgYAoKVGhlIHJlc3VsdHMgZnJvbSB0aGUgQnJldXNjaC1QYWdhbiwgS29lbmtlci1CYXNzZXR0LCBhbmQgV2hpdGUncyB0ZXN0cyBhbGwgZGV0ZWN0IGhldGVyb3NjZWRhc3RpY2l0eSBpbiB0aGUgbW9kZWwsIGFzIGFsbCBwLXZhbHVlcyBhcmUgZXh0cmVtZWx5IGxvdy4gVGhpcyBjb25maXJtcyBhIGNsZWFyIHZpb2xhdGlvbiBvZiB0aGUgaG9tb3NjZWRhc3RpY2l0eSBhc3N1bXB0aW9uIGluIE9MUyByZWdyZXNzaW9uLiAKCmBgYHtyIGhldGVyb3NjZWRhc3RpY2l0eSB0ZXN0cywgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KCiMgQnJldXNjaC1QYWdhbiBUZXN0CmJwdGVzdChPTFMsIHN0dWRlbnRpemU9RkFMU0UpCgojIEtvZW5rZXItQmFzc2V0dCBUZXN0CmJwdGVzdChPTFMpIAoKIyBXaGl0ZSBUZXN0CndoaXRlX3Rlc3QoT0xTKQoKCmBgYAoKQ29tcGFyaW5nIHRvIHRoZSBzY2F0dGVyIHBsb3Qgd2UgbWFkZSB0byBpZGVudGlmeSBoZXRlcm9zY2VkYXN0aWNpdHkgZnJvbSB0aGUgcHJldmlvdXMgYXNzaWdubWVudCwgdGhlIHJlc2lkdWFscyBpbiB0aGlzIHNjYXR0ZXIgcGxvdCBzaG93IG5vIGRpc2Nlcm5pYmxlIHRyZW5kIG9mIHJpc2luZyBvciBmYWxsaW5nIHZhcmlhbmNlIHdpdGggaW5jcmVhc2luZyBmaXR0ZWQgdmFsdWVzOyBpbnN0ZWFkLCB0aGV5IHNlZW0gdG8gYmUgcHJldHR5IHVuaWZvcm1seSBkaXN0cmlidXRlZCBhcm91bmQgdGhlIGhvcml6b250YWwgbGluZSBhdCB6ZXJvLiBSZWdhcmRsZXNzLCB0aGUgQnJldXNjaC1QYWdhbiB0ZXN0IGlzIG9mdGVuIG1vcmUgc2Vuc2l0aXZlIHRoYW4gYSByZXNpZHVhbCBwbG90LiBFdmVuIHNtYWxsIGRldmlhdGlvbnMgdGhhdCBhcmUgaGFyZCB0byBzZWUgdmlzdWFsbHkgbWF5IGJlIGRldGVjdGVkLgoKCmBgYHtyIGhldGVyb3NjZWRhc3RpY2l0eSBwbG90LCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQoKZ2dwbG90KHJlZ0RhdGEsIGFlcyh4ID0gRml0dGVkLCB5ID0gU3RhbmRhcmRpemVkX1Jlc2lkdWFscykpICsKICBnZW9tX3BvaW50KGNvbG9yID0gIiMyODNkM2IiLCBhbHBoYSA9IDAuOSwgc2l6ZSA9IDAuNikgKyAgICAKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBsaW5ldHlwZSA9ICJkYXNoZWQiLCBjb2xvciA9ICIjYzQ0NTM2Iiwgc2l6ZSA9IDEpICsgICAjCiAgbGFicygKICAgIHRpdGxlID0gIlNjYXR0ZXIgUGxvdCBvZiBTdGFuZGFyZGl6ZWQgUmVzaWR1YWxzIHZzIEZpdHRlZCBWYWx1ZXMiLAogICAgeCA9ICJGaXR0ZWQgVmFsdWVzIiwKICAgIHkgPSAiU3RhbmRhcmRpemVkIFJlc2lkdWFscyIKICApICsKICB0aGVtZV9saWdodCgpICsgICAKICB0aGVtZShwbG90LnN1YnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSA5LGZhY2UgPSAiaXRhbGljIiksCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIsIGZhY2UgPSAiYm9sZCIpLCAKICAgICAgICBheGlzLnRleHQueD1lbGVtZW50X3RleHQoc2l6ZT02KSwKICAgICAgICBheGlzLnRleHQueT1lbGVtZW50X3RleHQoc2l6ZT02KSwgCiAgICAgICAgYXhpcy50aXRsZT1lbGVtZW50X3RleHQoc2l6ZT04KSkKYGBgCgpUaGUgcmVzdWx0cyBvZiB0aGUgSmFycXVlLUJlcmEgdGVzdCBpbmRpY2F0ZSBhIHNpZ25pZmljYW50IGRldmlhdGlvbiBmcm9tIG5vcm1hbGl0eSBpbiB0aGUgcmVzaWR1YWxzLiBUaGUgcC12YWx1ZSBpcyB3ZWxsIGJlbG93IHR5cGljYWwgc2lnbmlmaWNhbmNlIGxldmVscywgYW5kIHJlamVjdHMgdGhlIG51bGwgaHlwb3RoZXNpcyB0aGF0IHRoZSByZXNpZHVhbHMgYXJlIG5vcm1hbGx5IGRpc3RyaWJ1dGVkLiBUaGVyZWZvcmUsIHRoZSB0ZXN0IHJlc3VsdHMgc3VnZ2VzdCB0aGF0IHRoZSByZXNpZHVhbHMgZG8gbm90IG1lZXQgdGhlIG5vcm1hbGl0eSBhc3N1bXB0aW9uIHJlcXVpcmVkIGZvciBPTFMgcmVncmVzc2lvbi4KCmBgYHtyIG5vcm1hbGl0eSBvZiBlcnJvcnMsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CgojIEphcnF1ZS1CZXJhIFRlc3QgCmphcnF1ZS5iZXJhLnRlc3QoT0xTJHJlc2lkdWFscykKCmBgYAoKQ29tcGFyaW5nIHRvIHRoZSBoaXN0b2dyYW0gb2Ygc3RhbmRhcmRpemVkIHJlc2lkdWFscyBmcm9tIHRoZSBwcmV2aW91cyBhc3NpZ25tZW50LCB3ZSBtYXkgYWxzbyBub3RpY2UgdGhhdCB0aGUgcmVzaWR1YWxzIGFyZSBub3QgcGVyZmVjdGx5IG5vcm1hbC4gVGhlIGhpc3RvZ3JhbSByZXZlYWxzIGEgc2xpZ2h0IGRlcGFydHVyZSBmcm9tIGEgbm9ybWFsIGRpc3RyaWJ1dGlvbiBhbmQgaXMgbGVmdCBza2V3ZWQuIERlc3BpdGUgdGhhdCB0aGUgc2tld25lc3MgaXMgbm90IHZlcnkgcHJvbm91bmNlZCwgaXQgaXMgc3RpbGwgY29uc2lzdGVudCB3aXRoIHRoZSBKYXJxdWUtQmVyYSB0ZXN0IHJlc3VsdHMuIAoKCmBgYHtyIGhpc3RvZ3JhbSBvZiByZXNpZHVhbHMsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CgpnZ3Bsb3QocmVnRGF0YSwgYWVzKHggPSBTdGFuZGFyZGl6ZWRfUmVzaWR1YWxzKSkgKwogIGdlb21faGlzdG9ncmFtKGJpbnMgPSAzMCwgZmlsbCA9ICIjMjgzZDNiIiwgYWxwaGEgPSAwLjkpICsKICBsYWJzKHRpdGxlID0gIkhpc3RvZ3JhbSBvZiBTdGFuZGFyZGl6ZWQgUmVzaWR1YWxzIiwgCiAgICAgICB4ID0gIlN0YW5kYXJkaXplZCBSZXNpZHVhbHMiLCAKICAgICAgIHkgPSAiRnJlcXVlbmN5IikgKwogIHRoZW1lX2xpZ2h0KCkgKyAgIAogIHRoZW1lKHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDksZmFjZSA9ICJpdGFsaWMiKSwKICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiwgZmFjZSA9ICJib2xkIiksIAogICAgICAgIGF4aXMudGV4dC54PWVsZW1lbnRfdGV4dChzaXplPTYpLAogICAgICAgIGF4aXMudGV4dC55PWVsZW1lbnRfdGV4dChzaXplPTYpLCAKICAgICAgICBheGlzLnRpdGxlPWVsZW1lbnRfdGV4dChzaXplPTgpKQpgYGAKClRoZSBzY2F0dGVycGxvdCBiZWxvdyBzaG93cyB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gdGhlIHN0YW5kYXJkaXplZCByZXNpZHVhbHMgb2YgdGhlIE9MUyBtb2RlbCBhbmQgdGhlIHJlc2lkdWFscyBvZiB0aGVpciBuZWFyZXN0IG5laWdoYm9ycy4gVGhlIHVwd2FyZC1zbG9waW5nIHRyZW5kIGxpbmUgaW5kaWNhdGVzIGEgcG9zaXRpdmUgcmVsYXRpb25zaGlwIGJldHdlZW4gdGhlc2UgcmVzaWR1YWxzIGFuZCB0aGVpciBuZWlnaGJvcnMsIHN1Z2dlc3Rpbmcgc3BhdGlhbCBhdXRvY29ycmVsYXRpb24uIFRoZSBjb2VmZmljaWVudCBmb3IgdGhlIHJlc2lkdWFscyBvZiB0aGVpciBuZWFyZXN0IG5laWdoYm9ycyBpcyAwLjczMjMsIHdpdGggYSBoaWdobHkgc2lnbmlmaWNhbnQgcC12YWx1ZSwgZGVtb25zdHJhdGluZyBhIHN0cm9uZyBwb3NpdGl2ZSByZWxhdGlvbnNoaXAuIFRoaXMgaW1wbGllcyB0aGF0IHJlc2lkdWFscyBhcmUgcG9zaXRpdmVseSBjb3JyZWxhdGVkIHdpdGggdGhvc2Ugb2YgdGhlaXIgY2xvc2VzdCBuZWlnaGJvcnMsIGltcGx5aW5nIHNwYXRpYWwgZGVwZW5kZW5jZS4KCmBgYHtyIG9scyByZXNpZHVhbHMgdnMgbmVhcmVzdCBuZWlnaGJvciByZXNpZHVhbHMsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGluY2x1ZGU9RkFMU0V9CgpyZXMubG0gPC0gbG0oU3RhbmRhcmRpemVkX1Jlc2lkdWFscyB+IFJlc2lkdWFsc19OQiwgZGF0YT1yZWdEYXRhKQpzdW1tYXJ5KHJlcy5sbSkKCmBgYAoKCmBgYHtyIG9scyByZXNpZHVhbHMgdnMgbmVhcmVzdCBuZWlnaGJvciByZXNpZHVhbHMgcGxvdCwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KZ2dwbG90KHJlZ0RhdGEsIGFlcyh4ID0gUmVzaWR1YWxzX05CLCB5ID0gU3RhbmRhcmRpemVkX1Jlc2lkdWFscykpICsKICBnZW9tX3BvaW50KGNvbG9yID0gIiMyODNkM2IiLCBhbHBoYSA9IDAuOSwgc2l6ZSA9IDAuNikgKwogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIHNlID0gRkFMU0UsIGNvbG9yID0gIiNjNDQ1MzYiLCBzaXplID0gMSkgKwogIGxhYnModGl0bGUgPSAiUmVzaWR1YWxzIHZzLiBOZWFyZXN0IE5laWdoYm9yIFJlc2lkdWFscyIsCiAgICAgICB4ID0gIk5lYXJlc3QgTmVpZ2hib3IgUmVzaWR1YWxzIiwKICAgICAgIHkgPSAiU3RhbmRhcmRpemVkIFJlc2lkdWFscyIpICsKICB0aGVtZV9saWdodCgpICsgICAKICB0aGVtZShwbG90LnN1YnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSA5LGZhY2UgPSAiaXRhbGljIiksCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIsIGZhY2UgPSAiYm9sZCIpLCAKICAgICAgICBheGlzLnRleHQueD1lbGVtZW50X3RleHQoc2l6ZT02KSwKICAgICAgICBheGlzLnRleHQueT1lbGVtZW50X3RleHQoc2l6ZT02KSwgCiAgICAgICAgYXhpcy50aXRsZT1lbGVtZW50X3RleHQoc2l6ZT04KSkKYGBgCgpUaGUgTW9yYW7igJlzIEkgc2NhdHRlcnBsb3QgYW5kIHRoZSByZXN1bHRzIGZyb20gdGhlIHBlcm11dGF0aW9ucyBmb3IgT0xTIHJlZ3Jlc3Npb24gcmVzaWR1YWxzIGJvdGggaW5kaWNhdGUgc2lnbmlmaWNhbnQgc3BhdGlhbCBhdXRvY29ycmVsYXRpb24uIFRoZSBzY2F0dGVycGxvdCBzaG93cyBhIHBvc2l0aXZlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHRoZSBsb2dnZWQgbWVkaWFuIGhvdXNlIHZhbHVlcyBhbmQgdGhlaXIgc3BhdGlhbGx5IGxhZ2dlZCB2YWx1ZXMsIHdpdGggYSBwb3NpdGl2ZSBzbG9wZSwgY29uZmlybWluZyB0aGF0IGhpZ2ggdmFsdWVzIHRlbmQgdG8gYmUgbmVhciBvdGhlciBoaWdoIHZhbHVlcywgYW5kIGxvdyB2YWx1ZXMgY2x1c3RlciB3aXRoIG90aGVyIGxvdyB2YWx1ZXMuIFRoZSBNb3JhbidzIEkgc3RhdGlzdGljIGZyb20gdGhlIE1vbnRlIENhcmxvIHNpbXVsYXRpb24gaXMgYXBwcm94aW1hdGVseSAwLjMsIHdpdGggYW4gZXh0cmVtZWx5IGxvdyBwLXZhbHVlLCBjb25maXJtaW5nIHRoYXQgdGhpcyBzcGF0aWFsIGF1dG9jb3JyZWxhdGlvbiBpcyBzdGF0aXN0aWNhbGx5IHNpZ25pZmljYW50LgoKVGhpcyBzaWduaWZpY2FudCBzcGF0aWFsIGF1dG9jb3JyZWxhdGlvbiBpbiB0aGUgT0xTIHJlc2lkdWFscyBpcyBwcm9ibGVtYXRpYyBiZWNhdXNlIGl0IHZpb2xhdGVzIHRoZSBPTFMgYXNzdW1wdGlvbiBvZiBpbmRlcGVuZGVudCByZXNpZHVhbHMuIFdoZW4gcmVzaWR1YWxzIGFyZSBzcGF0aWFsbHkgYXV0b2NvcnJlbGF0ZWQsIGl0IHN1Z2dlc3RzIHRoYXQgdGhlIG1vZGVsIGlzIG1pc3Npbmcgc3BhdGlhbCBzdHJ1Y3R1cmUgaW4gdGhlIGRhdGEsIHdoaWNoIGNvdWxkIGxlYWQgdG8gYmlhc2VkIG9yIGluZWZmaWNpZW50IGVzdGltYXRlcy4KCgpgYGB7ciBtb3JhbiBJIG9mIE9MUyByZXNpZHVhbHMsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CgpPTFNfbW9yYW5NQzwtbW9yYW4ubWMoc3RhbmRhcmRpemVkX3Jlc2lkdWFscywgcXVlZW5saXN0LCBuc2ltPTk5OSwgYWx0ZXJuYXRpdmU9InR3by5zaWRlZCIpIApPTFNfbW9yYW5NQwoKYGBgCkJvdGggdGhlIE1vcmFu4oCZcyBJIHN0YXRpc3RpYyBhbmQgdGhlIHBvc2l0aXZlIGJldGEgY29lZmZpY2llbnQgZnJvbSB0aGUgcmVncmVzc2lvbiBvZiBzdGFuZGFyZGl6ZWQgcmVzaWR1YWxzIG9uIHRoZWlyIG5lYXJlc3QgbmVpZ2hib3JzIHRlbGwgYSBzaW1pbGFyIHN0b3J5LiBUaGV5IGJvdGggcmV2ZWFsIHRoYXQgc3BhdGlhbCBkZXBlbmRlbmNlIGlzIHByZXNlbnQgaW4gdGhlIHJlc2lkdWFscywgc3VnZ2VzdGluZyB0aGF0IGEgc3BhdGlhbCBtb2RlbCwgc3VjaCBhcyBHZW9ncmFwaGljYWxseSBXZWlnaHRlZCBSZWdyZXNzaW9uIChHV1IpIG9yIGEgc3BhdGlhbCBhdXRvcmVncmVzc2l2ZSBtb2RlbCwgd291bGQgYmUgbW9yZSBhcHByb3ByaWF0ZSBmb3IgY2FwdHVyaW5nIHRoZSB1bmRlcmx5aW5nIHNwYXRpYWwgcmVsYXRpb25zaGlwcyBpbiB0aGUgZGF0YS4KCgpgYGB7ciBtb3JhbiBJIG9mIE9MUyByZXNpZHVhbHMgaGlzdG9ncmFtIGFuZCBzY2F0dGVycGxvdCwgZmlnLndpZHRoPTEwLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQoKcGx0MSA8LSBnZ3Bsb3QoZGF0YS5mcmFtZShyZXMgPSBPTFNfbW9yYW5NQyRyZXMpLCBhZXMoeCA9IHJlcykpICsKICBnZW9tX2hpc3RvZ3JhbShiaW5zID0gMTAwLCBmaWxsID0gIiMyODNkM2IiKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID1PTFNfbW9yYW5NQyRzdGF0aXN0aWMsIGNvbG9yID0gIiNjNDQ1MzYiLCBsaW5ldHlwZSA9ICdkYXNoZWQnLCBzaXplID0gMSkgKwogIGxhYnModGl0bGUgPSAiT2JzZXJ2ZWQgYW5kIFBlcm11dGVkIE1vcmFuJ3MgSSBvZiBPTFMgUmVzaWR1YWxzIiwKICAgICAgIHN1YnRpdGxlID0gIk9ic2VydmVkIE1vcmFuJ3MgSSBpbiBSZWQiLAogICAgICAgeCA9ICJNb3JhbidzIEkiLAogICAgICAgeSA9ICJDb3VudCIpICsKICB0aGVtZV9saWdodCgpICsgICAKICB0aGVtZShwbG90LnN1YnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSA5LGZhY2UgPSAiaXRhbGljIiksCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIsIGZhY2UgPSAiYm9sZCIpLCAKICAgICAgICBheGlzLnRleHQueD1lbGVtZW50X3RleHQoc2l6ZT02KSwKICAgICAgICBheGlzLnRleHQueT1lbGVtZW50X3RleHQoc2l6ZT02KSwgCiAgICAgICAgYXhpcy50aXRsZT1lbGVtZW50X3RleHQoc2l6ZT04KSkKCnBsdDIgPC0gZ2dwbG90KGRhdGEgPSBkYXRhLmZyYW1lKAogIHJlc2lkdWFscyA9c3RhbmRhcmRpemVkX3Jlc2lkdWFscywKICBzcGF0aWFsX2xhZyA9IGxhZy5saXN0dyhxdWVlbmxpc3QsIHN0YW5kYXJkaXplZF9yZXNpZHVhbHMpCiksIGFlcyh4ID0gcmVzaWR1YWxzLCB5ID0gc3BhdGlhbF9sYWcpKSArCiAgZ2VvbV9wb2ludChjb2xvciA9ICIjMjgzZDNiIiwgYWxwaGEgPSAwLjksIHNpemUgPSAwLjYpICsgIAogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIGNvbG9yID0gIiNjNDQ1MzYiLCBzZSA9IEZBTFNFKSArIAogIGxhYnModGl0bGUgPSAiTW9yYW4ncyBJIFNjYXR0ZXIgUGxvdCBmb3IgT0xTIFJlc2lkdWFscyIsCiAgICAgICB4ID0gIkxvZ2dlZCBNZWRpYW4gSG91c2UgVmFsdWUiLAogICAgICAgeSA9ICJTcGF0aWFsIExhZyBvZiBMTk1FREhWQUwiKSArCiAgdGhlbWVfbGlnaHQoKSArICAgCiAgdGhlbWUocGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gOSxmYWNlID0gIml0YWxpYyIpLAogICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyLCBmYWNlID0gImJvbGQiKSwgCiAgICAgICAgYXhpcy50ZXh0Lng9ZWxlbWVudF90ZXh0KHNpemU9NiksCiAgICAgICAgYXhpcy50ZXh0Lnk9ZWxlbWVudF90ZXh0KHNpemU9NiksIAogICAgICAgIGF4aXMudGl0bGU9ZWxlbWVudF90ZXh0KHNpemU9OCkpCgpwbHQxICsgcGx0MgpgYGAKCgojIyBTcGF0aWFsIExhZyBhbmQgRXJyb3IgUmVncmVzc2lvbiBSZXN1bHRzCgojIyMgU3BhdGlhbCBMYWcgUmVncmVzc2lvbgoKSW4gdGhlIHNwYXRpYWwgbGFnIHJlZ3Jlc3Npb24gb3V0cHV0LCB3ZSBtYXkgc2VlIHRoYXQgdGhlIHRlcm0gXChcdGV4dHtMTk1FREhWQUx9XCksIHJlcHJlc2VudGVkIGJ5IFwoIFxyaG8gXCkgaW4gdGhlIG1vZGVsLCBoYXMgYW4gZXN0aW1hdGUgb2YgMC42NTEgYW5kIGFuIGV4dHJlbWVseSBzaWduaWZpY2FudCBwLXZhbHVlIChcKCBwIDwgMi4yMiBcdGltZXMgMTBeey0xNn0gXCkpLlRoaXMgaW5kaWNhdGVzIHRoYXQgbmVhcmJ5IHZhbHVlcyBvZiB0aGUgZGVwZW5kZW50IHZhbHVlIGluZmx1ZW5jZSBlYWNoIG90aGVyLiBUaGUgc2lnbmlmaWNhbnQgcG9zaXRpdmUgY29lZmZpY2llbnQgKFwoIFxyaG8gPSAwLjY1MSBcKSkgc3VnZ2VzdHMgYSBzdWJzdGFudGlhbCBwb3NpdGl2ZSBzcGF0aWFsIGxhZyBlZmZlY3QsIG1lYW5pbmcgdGhhdCBoaWdoZXIgbWVkaWFuIGhvbWUgdmFsdWVzIGluIG5laWdoYm9yaW5nIGFyZWFzIGFyZSBhc3NvY2lhdGVkIHdpdGggaGlnaGVyIG1lZGlhbiBob21lIHZhbHVlcyBpbiB0aGUgYXJlYSBiZWluZyBleGFtaW5lZC4KCkFsbCBwcmVkaWN0b3JzIGluIHRoZSBzcGF0aWFsIGxhZyBtb2RlbCBhcmUgc2lnbmlmaWNhbnQuIFwoXHRleHR7UENUVkFDQU5UfVwpIGhhcyBhIGNvZWZmaWNpZW50IG9mIC0wLjAwODUgYW5kIGlzIGhpZ2hseSBzaWduaWZpY2FudCBzaW5jZSBcKCBwIDwgMi4yMiBcdGltZXMgMTBeey0xNn0gXCkuIEl0IG1lYW5zIGEgaGlnaGVyIHZhY2FuY3kgcmF0ZSBpcyBhc3NvY2lhdGVkIHdpdGggbG93ZXIgbWVkaWFuIGhvbWUgdmFsdWVzLiBcKFx0ZXh0e1BDVFNJTkdMRVN9XCkgaGFzIGEgY29lZmZpY2llbnQgb2YgMC4wMDIwLCBzaWduaWZpY2FudCB3aXRoIGEgXCggcCA8IDAuMDAwMSBcKS4gVGhlIHBvc2l0aXZlIGFzc29jaWF0aW9uIHN1Z2dlc3RzIHRoYXQgYXJlYXMgd2l0aCBhIGhpZ2hlciBwcm9wb3J0aW9uIG9mIHNpbmdsZSBob3VzZWhvbGRzIG1heSBzbGlnaHRseSBpbmNyZWFzZSBtZWRpYW4gaG9tZSB2YWx1ZXMuIFwoXHRleHR7UENUQkFDSE1PUn1cKSBoYXMgYSBjb2VmZmljaWVudCBvZiAwLjAwODUgYW5kIGlzIGV4dHJlbWVseSBzaWduaWZpY2FudCAoXCggcCA8IDIuMjIgXHRpbWVzIDEwXnstMTZ9IFwpKS4gSGlnaGVyIGVkdWNhdGlvbiBsZXZlbHMgYXJlIHBvc2l0aXZlbHkgYXNzb2NpYXRlZCB3aXRoIGhvbWUgdmFsdWVzLCBtZWFuaW5nIHRoYXQgbW9yZSBlZHVjYXRlZCBhcmVhcyB0ZW5kIHRvIGhhdmUgaGlnaGVyIGhvbWUgdmFsdWVzLiBcKFx0ZXh0e0xOTkJFTFBPVn1cKSBoYXMgYSBjb2VmZmljaWVudCBvZiAtMC4wMzQxLCBhbHNvIGhpZ2hseSBzaWduaWZpY2FudCAoXCggcCA8IDEgXHRpbWVzIDEwXnstN30gXCkpLiBUaGUgbmVnYXRpdmUgYXNzb2NpYXRpb24gc3VnZ2VzdHMgdGhhdCBoaWdoZXIgcG92ZXJ0eSBsZXZlbHMgYXJlIGFzc29jaWF0ZWQgd2l0aCBsb3dlciBtZWRpYW4gaG9tZSB2YWx1ZXMuCgpUaGUgT0xTIG1vZGVsIGFsc28gc2hvd3Mgc2lnbmlmaWNhbnQgY29lZmZpY2llbnRzIGZvciBhbGwgcHJlZGljdG9ycywgYnV0IHdpdGggbGFyZ2VyIGVmZmVjdCBzaXplcy4gRm9yIGV4YW1wbGUsIFx0ZXh0e1BDVFZBQ0FOVH0gaGFzIGEgY29lZmZpY2llbnQgb2YgLTAuMDE5MiBpbiBPTFMsIGNvbXBhcmVkIHRvIC0wLjAwODUgaW4gc3BhdGlhbCBsYWcuIFRoaXMgc3VnZ2VzdHMgdGhhdCBPTFMgb3ZlcmVzdGltYXRlcyB0aGUgaW5mbHVlbmNlIG9mIHRoZXNlIHByZWRpY3RvcnMgZHVlIHRvIG9taXR0ZWQgc3BhdGlhbCBkZXBlbmRlbmNlLiBGb3IgdGhlIG90aGVyIHByZWRpY3RvcnMsIHRoZSBPTFMgY29lZmZpY2llbnRzIGFyZSBhbHNvIGxhcmdlciBpbiBtYWduaXR1ZGUgdGhhbiB0aGUgc3BhdGlhbCBsYWcgY29lZmZpY2llbnRzLiAKCmBgYHtyIHNwYXRpYWwgbGFnIHJlZ3Jlc3Npb24sIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CgpTTCA8LSBsYWdzYXJsbShMTk1FREhWQUwgfiBQQ1RWQUNBTlQgKyBQQ1RTSU5HTEVTICsgUENUQkFDSE1PUiArIExOTkJFTFBPViwgZGF0YT1yZWdEYXRhLCBxdWVlbmxpc3QpCnN1bW1hcnkoU0wpCgpgYGAKCldlIHJhbiBCcmV1c2NoLVBhZ2FuIHRlc3QgdG8gYXNzZXNzIHdoZXRoZXIgdGhlIHJlc2lkdWFscyBvZiB0aGUgc3BhdGlhbCBsYWcgcmVncmVzc2lvbiBtb2RlbCBleGhpYml0IGhldGVyb3NjZWRhc3RpY2l0eS4gQXMgd2UgbWF5IHNlZSwgdGhlIHRlc3Qgc3RhdGlzdGljIGZvciB0aGUgc3BhdGlhbCBsYWcgcmVncmVzc2lvbiBpcyBcKCBCUCA9IDIxMSBcKSB3aXRoIFwoIGRmID0gNCBcKSwgYW5kIFwoIHAgPCAyIFx0aW1lcyAxMF57LTE2fSBcKS4gR2l2ZW4gdGhlIGV4dHJlbWVseSBsb3cgcC12YWx1ZSwgd2UgcmVqZWN0IHRoZSBudWxsIGh5cG90aGVzaXMgb2YgaG9tb3NjZWRhc3RpY2l0eSwgaW5kaWNhdGluZyB0aGF0IHJlc2lkdWFscyBpbiB0aGUgc3BhdGlhbCBsYWcgcmVncmVzc2lvbiBtb2RlbCByZW1haW4gaGV0ZXJvc2NlZGFzdGljLgoKCmBgYHtyIFNMIGhldGVyb3NjZWRhc3RpY2l0eSB0ZXN0cywgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KCiMgQnJldXNjaC1QYWdhbiBUZXN0CmJwdGVzdC5TYXJsbShTTCwgc3R1ZGVudGl6ZT1GQUxTRSkKCmBgYAoKV2hlbiBjb21wYXJpbmcgdGhlIE9MUyBhbmQgc3BhdGlhbCBsYWcgcmVncmVzc2lvbiBtb2RlbHMsIHNldmVyYWwgbWV0cmljcyBzaG93IHRoZSBzcGF0aWFsIGxhZyBtb2RlbCBwcm92aWRlcyBhIGJldHRlciBmaXQuIFRoZSBzcGF0aWFsIGxhZyBtb2RlbCBoYXMgYSBzaWduaWZpY2FudGx5IGxvd2VyIEFJQyAoNTI1KSB0aGFuIE9MUyAoMTQzNSksIGluZGljYXRpbmcgYSBiZXR0ZXIgbW9kZWwgZml0IGJ5IHBlbmFsaXppbmcgbGVzcyBmb3IgYWRkZWQgY29tcGxleGl0eS4gU2ltaWxhcmx5LCB0aGUgU2Nod2FyeiBDcml0ZXJpb24gaXMgbXVjaCBsb3dlciBmb3IgdGhlIHNwYXRpYWwgbGFnIG1vZGVsLCBzdWdnZXN0aW5nIGl0IGNhcHR1cmVzIHRoZSBzdHJ1Y3R1cmUgb2YgdGhlIGRhdGEgbW9yZSBlZmZlY3RpdmVseSB0aGFuIHRoZSBPTFMgbW9kZWwuIFRoZSBzcGF0aWFsIGxhZyBtb2RlbCAoLTI1NikgaGFzIGEgaGlnaGVyIGxvZyBsaWtlbGlob29kIHRoYW4gT0xTICgtNzExKSwgbWVhbmluZyB0aGF0IGl0IGJldHRlciBleHBsYWlucyB0aGUgdmFyaWFiaWxpdHkgaW4gdGhlIGRhdGEuCgpgYGB7ciBjb21wYXJlIE9MUyBhbmQgU0wsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CgojIEFrYWlrZSBJbmZvcm1hdGlvbiBDcml0ZXJpb24KYWljX29scyA8LSBBSUMoT0xTKQphaWNfc2wgPC0gQUlDKFNMKQoKIyBTY2h3YXJ6IENyaXRlcmlvbgpiaWNfb2xzIDwtIEJJQyhPTFMpCmJpY19zbCA8LSBCSUMoU0wpCgojIFRoZSBMb2cgTGlrZWxpaG9vZApsb2dsaWtfb2xzIDwtIGxvZ0xpayhPTFMpCmxvZ2xpa19zbCA8LSBsb2dMaWsoU0wpCgpyZXN1bHRzIDwtIGRhdGEuZnJhbWUoCiAgTW9kZWwgPSBjKCJPTFMgUmVncmVzc2lvbiIsICJTcGF0aWFsIExhZyBSZWdyZXNzaW9uIiksCiAgQUlDID0gYyhhaWNfb2xzLCBhaWNfc2wpLAogIFNjaHdhcnpDcml0ZXJpb24gPSBjKGJpY19vbHMsIGJpY19zbCksCiAgTG9nTGlrZWxpaG9vZCA9IGMobG9nbGlrX29scywgbG9nbGlrX3NsKQopCgpyZXN1bHRzICU+JQogIGthYmxlKHJvdy5uYW1lcyA9IEZBTFNFKSAlPiUKICBrYWJsZV9zdHlsaW5nKGJvb3RzdHJhcF9vcHRpb25zID0gYygic3RyaXBlZCIsICJob3ZlciIsICJjb25kZW5zZWQiKSkgCgoKYGBgCgpUaGUgTGlrZWxpaG9vZCBSYXRpbyBUZXN0IGFzc2Vzc2VzIHRoZSBpbXByb3ZlbWVudCBpbiBtb2RlbCBmaXQgYmV0d2VlbiB0aGUgT0xTIGFuZCBzcGF0aWFsIGxhZyBtb2RlbHMsIGFuZCB0aGUgcmVzdWx0IHdlIGdldCBoZXJlIHNob3dzIFwoIExSID0gOTEyIFwpIHdpdGggXCggZGYgPSAxIFwpLCBhbmQgXCggcCA8IDIgXHRpbWVzIDEwXnstMTZ9IFwpLiBXaXRoIGEgbGFyZ2UgdGVzdCBzdGF0aXN0aWMgYW5kIGxvdyBwLXZhbHVlLCB3ZSBjb25jbHVkZSB0aGF0IHRoZSBzcGF0aWFsIGxhZyBtb2RlbCBzaWduaWZpY2FudGx5IGltcHJvdmVzIGZpdCBvdmVyIHRoZSBPTFMgbW9kZWwuIAoKYGBge3IgbG9nIGxpa2VsaWhvb2QgcmF0aW8gdGVzdCBmb3IgU0wsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CgojIFRoZSBMaWtlbGlob29kIFJhdGlvIFRlc3QKbHJfdGVzdCA8LSBMUi5TYXJsbShTTCwgT0xTKQpscl90ZXN0CgpgYGAKCkZpbmFsbHksIHdlIGV4YW1pbmVkIE1vcmFuJ3MgSSBmb3IgdGhlIHNwYXRpYWwgbGFnIHJlZ3Jlc3Npb24gbW9kZWwncyByZXNpZHVhbHMuVGhlIG9ic2VydmVkIE1vcmFu4oCZcyBJIG9mIC0wLjA4IHN1Z2dlc3RzIGEgc21hbGwgbmVnYXRpdmUgc3BhdGlhbCBhdXRvY29ycmVsYXRpb24gaW4gdGhlIHJlc2lkdWFscyBvZiB0aGUgc3BhdGlhbCBsYWcgbW9kZWwuIFdpdGggXCggcCA9IDAuMDAyIFwpLCB3ZSByZWplY3QgdGhlIG51bGwgaHlwb3RoZXNpcyBvZiBubyBzcGF0aWFsIGF1dG9jb3JyZWxhdGlvbi4gVGhpcyBuZWdhdGl2ZSBNb3JhbuKAmXMgSSBpbmRpY2F0ZXMgdGhhdCByZXNpZHVhbHMgYXJlIGRpc3RyaWJ1dGVkIHdpdGggc2xpZ2h0IHNwYXRpYWwgZGlzcGVyc2lvbiByYXRoZXIgdGhhbiBjbHVzdGVyaW5nLCBzdWdnZXN0aW5nIHRoZSBzcGF0aWFsIGxhZyBtb2RlbCBlZmZlY3RpdmVseSBhY2NvdW50cyBmb3IgbW9zdCBzcGF0aWFsIGRlcGVuZGVuY2llcyBpbiB0aGUgZGF0YS4KCmBgYHtyIG1vcmFuIEkgb2YgU0wgcmVzaWR1YWxzLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQoKU0xfbW9yYW5NYzwtbW9yYW4ubWMoU0wkcmVzaWR1YWxzLCBxdWVlbmxpc3QsOTk5LCBhbHRlcm5hdGl2ZT0idHdvLnNpZGVkIikKU0xfbW9yYW5NYwoKYGBgCgpCb3RoIHRoZSByZXNpZHVhbCBoaXN0b2dyYW1zIGFzIHdlbGwgYXMgdGhlIHNjYXR0ZXIgcGxvdCBzdXBwb3J0IHRoaXMgY29uY2x1c2lvbi4gVGhlIGhpc3RvZ3JhbSBvZiByZXNpZHVhbHMgaXMgYWxzbyBhcHByb3hpbWF0ZWx5IG5vcm1hbGx5IGRpc3RyaWJ1dGVkLCBhbmQgdGhlIHNjYXR0ZXIgcGxvdCBvZiByZXNpZHVhbHMgYWdhaW5zdCBmaXR0ZWQgdmFsdWVzIHNob3dzIG5vIGNsZWFyIHBhdHRlcm4gb3IgdHJlbmQuIEFsbCBvZiB0aGVzZSBzdWdnZXN0IHRoYXQgdGhlIHNwYXRpYWwgbGFnIG1vZGVsIGlzIGEgZ29vZCBmaXQgZm9yIHRoZSBkYXRhIGNvbXBhcmVkIHRvIE9MUy4gCgpgYGB7ciBtb3JhbiBJIG9mIFNMIHJlc2lkdWFscyBoaXN0b2dyYW0gYW5kIHNjYXR0ZXJwbG90LCBmaWcud2lkdGg9MTAsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CgpwbHQzIDwtIGdncGxvdChkYXRhLmZyYW1lKHJlcyA9IFNMJHJlc2lkdWFscyksIGFlcyh4ID0gcmVzKSkgKwogIGdlb21faGlzdG9ncmFtKGJpbnMgPSAxMDAsIGZpbGwgPSAiIzI4M2QzYiIpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPVNMX21vcmFuTWMkc3RhdGlzdGljLCBjb2xvciA9ICIjYzQ0NTM2IiwgbGluZXR5cGUgPSAnZGFzaGVkJywgc2l6ZSA9IDEpICsKICBsYWJzKHRpdGxlID0gIk9ic2VydmVkIGFuZCBQZXJtdXRlZCBNb3JhbidzIEkgb2YgU0wgUmVzaWR1YWxzIiwKICAgICAgIHN1YnRpdGxlID0gIk9ic2VydmVkIE1vcmFuJ3MgSSBpbiBSZWQiLAogICAgICAgeCA9ICJNb3JhbidzIEkiLAogICAgICAgeSA9ICJDb3VudCIpICsKICB0aGVtZV9saWdodCgpICsgICAKICB0aGVtZShwbG90LnN1YnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSA5LGZhY2UgPSAiaXRhbGljIiksCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIsIGZhY2UgPSAiYm9sZCIpLCAKICAgICAgICBheGlzLnRleHQueD1lbGVtZW50X3RleHQoc2l6ZT02KSwKICAgICAgICBheGlzLnRleHQueT1lbGVtZW50X3RleHQoc2l6ZT02KSwgCiAgICAgICAgYXhpcy50aXRsZT1lbGVtZW50X3RleHQoc2l6ZT04KSkKCnBsdDQgPC0gZ2dwbG90KGRhdGEgPSBkYXRhLmZyYW1lKAogIHJlc2lkdWFscyA9U0wkcmVzaWR1YWxzLAogIHNwYXRpYWxfbGFnID0gbGFnLmxpc3R3KHF1ZWVubGlzdCwgU0wkcmVzaWR1YWxzKQopLCBhZXMoeCA9IHJlc2lkdWFscywgeSA9IHNwYXRpYWxfbGFnKSkgKwogIGdlb21fcG9pbnQoY29sb3IgPSAiIzI4M2QzYiIsIGFscGhhID0gMC45LCBzaXplID0gMC42KSArICAKICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBjb2xvciA9ICIjYzQ0NTM2Iiwgc2UgPSBGQUxTRSkgKyAKICBsYWJzKHRpdGxlID0gIk1vcmFuJ3MgSSBTY2F0dGVyIFBsb3QgZm9yIFNMIFJlc2lkdWFscyIsCiAgICAgICB4ID0gIkxvZ2dlZCBNZWRpYW4gSG91c2UgVmFsdWUiLAogICAgICAgeSA9ICJTcGF0aWFsIExhZyBvZiBMTk1FREhWQUwiKSArCiAgdGhlbWVfbGlnaHQoKSArICAgCiAgdGhlbWUocGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gOSxmYWNlID0gIml0YWxpYyIpLAogICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyLCBmYWNlID0gImJvbGQiKSwgCiAgICAgICAgYXhpcy50ZXh0Lng9ZWxlbWVudF90ZXh0KHNpemU9NiksCiAgICAgICAgYXhpcy50ZXh0Lnk9ZWxlbWVudF90ZXh0KHNpemU9NiksIAogICAgICAgIGF4aXMudGl0bGU9ZWxlbWVudF90ZXh0KHNpemU9OCkpCgpwbHQzICsgcGx0NApgYGAKCgojIyMgU3BhdGlhbCBFcnJvciBSZWdyZXNzaW9uCgpJbiB0aGUgc3BhdGlhbCBlcnJvciByZWdyZXNzaW9uIG1vZGVsLCB0aGUgdGVybSBcKFxsYW1iZGFcKSByZXByZXNlbnRzIHRoZSBzcGF0aWFsIGF1dG9jb3JyZWxhdGlvbiB3aXRoaW4gdGhlIG1vZGVs4oCZcyBlcnJvciB0ZXJtcy4gSW4gdGhpcyBjYXNlLCBcKFxsYW1iZGFcKSBpcyBlc3RpbWF0ZWQgYXQgMC44MTUgYW5kIGlzIHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQsIHdpdGggXCggcCA8IDIuMjIgXHRpbWVzIDEwXnstMTZ9IFwpLiBUaGlzIGhpZ2hseSBzaWduaWZpY2FudCBhbmQgbGFyZ2UgdmFsdWUgb2YgXChcbGFtYmRhXCkgc3VnZ2VzdHMgYSBzdHJvbmcgc3BhdGlhbCBkZXBlbmRlbmN5IGluIHRoZSBlcnJvciB0ZXJtcy4gCgpFeGFtaW5pbmcgdGhlIGluZGl2aWR1YWwgcHJlZGljdG9ycyBpbiB0aGUgbW9kZWwsIGFsbCB2YXJpYWJsZXMgYXJlIHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQgYXQgYSBoaWdoIGNvbmZpZGVuY2UgbGV2ZWwuIFwoXHRleHR7UENUVkFDQU5UfVwpIGhhcyBhbiBlc3RpbWF0ZSBvZiAtMC4wMDU4IChcKCBwIDwgNi45NCBcdGltZXMgMTBeey05fSBcKSksIGluZGljYXRpbmcgdGhhdCB2YWNhbmN5IHJhdGVzIG5lZ2F0aXZlbHkgYWZmZWN0IG1lZGlhbiBob21lIHZhbHVlcy4gXChcdGV4dHtQQ1RTSU5HTEVTfVwpIGhhcyBhIHBvc2l0aXZlIGNvZWZmaWNpZW50IG9mIDAuMDAyNyAoXCggcCA8IDEuNjEgXHRpbWVzIDEwXnstNX0gXCkpLCBzdWdnZXN0aW5nIGEgc21hbGwgcG9zaXRpdmUgYXNzb2NpYXRpb24gd2l0aCBtZWRpYW4gaG9tZSB2YWx1ZXMuIFwoXHRleHR7UENUQkFDSE1PUn1cKSAsIHJlcHJlc2VudGluZyB0aGUgcGVyY2VudGFnZSBvZiBiYWNoZWxvcuKAmXMgZGVncmVlcyBvciBoaWdoZXIsIHNob3dzIGEgcG9zaXRpdmUgZWZmZWN0IHdpdGggYW4gZXN0aW1hdGUgb2YgMC4wMDk4IChcKCBwIDwgMi4yMCBcdGltZXMgMTBeey0xNn0gXCkpLCBpbmRpY2F0aW5nIHRoYXQgaGlnaGVyIGVkdWNhdGlvbiBsZXZlbHMgY29ycmVsYXRlIHdpdGggaGlnaGVyIGhvbWUgdmFsdWVzLiBcKFx0ZXh0e0xOTkJFTFBPVn1cKSBoYXMgYSBuZWdhdGl2ZSBlc3RpbWF0ZSBvZiAtMC4wMzQ1IGFuZCBcKCBwIDwgMS4xMSBcdGltZXMgMTBeey02fSBcKSwgaW1wbHlpbmcgdGhhdCBoaWdoZXIgbGV2ZWxzIG9mIG5laWdoYm9yaG9vZCBwb3ZlcnR5IGFyZSBhc3NvY2lhdGVkIHdpdGggbG93ZXIgbWVkaWFuIGhvbWUgdmFsdWVzLgoKU2ltaWxhciB0byBzcGF0aWFsIGxhZyByZWdyZXNzaW9uLCB3aGVuIGNvbXBhcmluZyB0aGVzZSByZXN1bHRzIHdpdGggdGhlIE9MUyByZWdyZXNzaW9uIG1vZGVsLCB3ZSBvYnNlcnZlIHRoYXQgdGhlIGNvZWZmaWNpZW50cyBmb3Igb3VyIHByZWRpY3RvcnMgYXJlIGFsbCBzbWFsbGVyIGluIG1hZ25pdHVkZSB0aGFuIHRoZWlyIE9MUyBjb3VudGVycGFydHMuIEZvciBpbnN0YW5jZSwgXHRleHR7UENUVkFDQU5UfSBoYWQgYSBjb2VmZmljaWVudCBvZiAtMC4wMTkxNTYgaW4gdGhlIE9MUyBtb2RlbCwgd2hpbGUgaW4gdGhlIHNwYXRpYWwgZXJyb3IgbW9kZWwsIGl0IGlzIHJlZHVjZWQgdG8gLTAuMDA1OC4gVGhpcyByZWR1Y3Rpb24gaW4gY29lZmZpY2llbnQgbWFnbml0dWRlIHN1Z2dlc3RzIHRoYXQgdGhlIHNwYXRpYWwgZXJyb3IgbW9kZWwgcHJvdmlkZXMgYSBtb3JlIGNvbnNlcnZhdGl2ZSBlc3RpbWF0ZSBvZiB0aGUgZWZmZWN0cyBvZiB0aGVzZSBwcmVkaWN0b3JzIG9uIG1lZGlhbiBob21lIHZhbHVlcywgbGlrZWx5IGR1ZSB0byB0aGUgYWNjb3VudGVkIHNwYXRpYWwgYXV0b2NvcnJlbGF0aW9uLgoKCmBgYHtyIHNwYXRpYWwgZXJyb3IgcmVncmVzc2lvbiwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KClNFIDwtIGVycm9yc2FybG0oTE5NRURIVkFMIH4gUENUVkFDQU5UICsgUENUU0lOR0xFUyArIFBDVEJBQ0hNT1IgKyBMTk5CRUxQT1YsIGRhdGE9cmVnRGF0YSwgcXVlZW5saXN0KQpzdW1tYXJ5KFNFKQoKYGBgCgpCYXNlZCBvbiB0aGUgcmVzdWx0cyBvZiB0aGUgQnJldXNjaC1QYWdhbiB0ZXN0LCB0aGUgc3BhdGlhbCBsYWcgcmVncmVzc2lvbiByZXNpZHVhbHMgYXJlIGluZGVlZCBoZXRlcm9zY2VkYXN0aWMuIFRoZSB0ZXN0IHN0YXRpc3RpYyBpcyBcKCBCUCA9IDIzIFwpIHdpdGggXCggZGYgPSA0IFwpLCBhbmQgXCggcCA8IDAuMDAwMSBcKS4gU2luY2UgdGhlIHAtdmFsdWUgaXMgc2lnbmlmaWNhbnRseSBsb3dlciB0aGFuIHRoZSBjb252ZW50aW9uYWwgYWxwaGEgbGV2ZWxzICgwLjAxLCAwLjA1KSwgd2UgcmVqZWN0IHRoZSBudWxsIGh5cG90aGVzaXMgb2YgaG9tb3NjZWRhc3RpY2l0eS4gVGhpcyBpbmRpY2F0ZXMgdGhhdCB0aGUgdmFyaWFuY2Ugb2YgdGhlIHJlc2lkdWFscyBpcyBub3QgY29uc3RhbnQgYWNyb3NzIG9ic2VydmF0aW9ucywgc3VnZ2VzdGluZyB0aGUgcHJlc2VuY2Ugb2YgaGV0ZXJvc2NlZGFzdGljaXR5IGluIHRoZSBtb2RlbCdzIHJlc2lkdWFscy4KCmBgYHtyIFNFIGhldGVyb3NjZWRhc3RpY2l0eSB0ZXN0cywgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KCiMgQnJldXNjaC1QYWdhbiBUZXN0IApicHRlc3QuU2FybG0oU0UsIHN0dWRlbnRpemU9RkFMU0UpCgpgYGAKCldlIGFsc28gY29tcGFyZWQgdGhlIHNwYXRpYWwgZXJyb3IgbW9kZWwgdG8gdGhlIE9MUyBtb2RlbCB1c2luZyB0aGUgQUlDLCBTQywgbG9nLWxpa2VsaWhvb2QsIGFuZCBsaWtlbGlob29kIHJhdGlvIHRlc3QuIFRoZSBzcGF0aWFsIGVycm9yIG1vZGVsIGhhcyBhIGxvd2VyIEFJQyAoNzU5KSBhbmQgU0MgKDc5OCkgdGhhbiB0aGUgT0xTIG1vZGVsICgxNDM1IGFuZCAxNDY4LCByZXNwZWN0aXZlbHkpLCBpbmRpY2F0aW5nIGEgYmV0dGVyIGZpdC4gVGhlIGxvZy1saWtlbGlob29kIG9mIHRoZSBzcGF0aWFsIGVycm9yIG1vZGVsICgtMzczKSBpcyBhbHNvIGhpZ2hlciB0aGFuIHRoYXQgb2YgdGhlIE9MUyBtb2RlbCAoLTcxMSksIHN1Z2dlc3RpbmcgdGhhdCB0aGUgc3BhdGlhbCBlcnJvciBtb2RlbCBiZXR0ZXIgZXhwbGFpbnMgdGhlIHZhcmlhYmlsaXR5IGluIHRoZSBkYXRhLgoKYGBge3IgY29tcGFyZSBPTFMgU0wgYW5kIFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQoKIyBBa2Fpa2UgSW5mb3JtYXRpb24gQ3JpdGVyaW9uCmFpY19zZSA8LSBBSUMoU0UpCgojIFNjaHdhcnogQ3JpdGVyaW9uCmJpY19zZSA8LSBCSUMoU0UpCgojIFRoZSBMb2cgTGlrZWxpaG9vZApsb2dsaWtfc2UgPC0gbG9nTGlrKFNFKQoKcmVzdWx0cyA8LSBkYXRhLmZyYW1lKAogIE1vZGVsID0gYygiT0xTIFJlZ3Jlc3Npb24iLCAiU3BhdGlhbCBMYWcgUmVncmVzc2lvbiIsICJTcGF0aWFsIEVycm9yIFJlZ3Jlc3Npb24iKSwKICBBSUMgPSBjKGFpY19vbHMsIGFpY19zbCwgYWljX3NlKSwKICBTY2h3YXJ6Q3JpdGVyaW9uID0gYyhiaWNfb2xzLCBiaWNfc2wsIGJpY19zZSksCiAgTG9nTGlrZWxpaG9vZCA9IGMobG9nbGlrX29scywgbG9nbGlrX3NsLCBsb2dsaWtfc2UpCikKCnJlc3VsdHMgJT4lCiAga2FibGUocm93Lm5hbWVzID0gRkFMU0UpICU+JQogIGthYmxlX3N0eWxpbmcoYm9vdHN0cmFwX29wdGlvbnMgPSBjKCJzdHJpcGVkIiwgImhvdmVyIiwgImNvbmRlbnNlZCIpKSAKCgpgYGAKCkFjY29yZGluZyB0byB0aGUgTGlrZWxpaG9vZCBSYXRpbyBUZXN0LCB3ZSBzZWUgXCggTFIgPSA2NzggXCkgd2l0aCBcKCBkZiA9IDEgXCksIGFuZCBcKCBwIDwgMiBcdGltZXMgMTBeey0xNn0gXCkuIFdpdGggYSBsYXJnZSB0ZXN0IHN0YXRpc3RpYyBhbmQgbG93IHAtdmFsdWUsIHdlIG1heSBhbHNvIGNvbmNsdWRlIHRoYXQgdGhlIHNwYXRpYWwgZXJyb3IgbW9kZWwgc2lnbmlmaWNhbnRseSBpbXByb3ZlcyBmaXQgb3ZlciB0aGUgT0xTIG1vZGVsLiAKCmBgYHtyIGxvZyBsaWtlbGlob29kIHJhdGlvIHRlc3QgZm9yIFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQoKbHJfdGVzdCA8LSBMUi5TYXJsbShTRSwgT0xTKQpscl90ZXN0CgpgYGAKCkZpbmFsbHksIHdlIGV4YW1pbmVkIE1vcmFuJ3MgSSBmb3IgdGhlIHNwYXRpYWwgZXJyb3IgcmVncmVzc2lvbiBtb2RlbCdzIHJlc2lkdWFscy4gVGhlIG9ic2VydmVkIE1vcmFu4oCZcyBJIG9mIC0wLjA5IHN1Z2dlc3RzIGEgc21hbGwgbmVnYXRpdmUgc3BhdGlhbCBhdXRvY29ycmVsYXRpb24gaW4gdGhlIHJlc2lkdWFscyBvZiB0aGUgc3BhdGlhbCBlcnJvciBtb2RlbC4gCldpdGggXCggcCA9IDAuMDAyIFwpLCB3ZSByZWplY3QgdGhlIG51bGwgaHlwb3RoZXNpcyBvZiBubyBzcGF0aWFsIGF1dG9jb3JyZWxhdGlvbi4gVGhpcyBuZWdhdGl2ZSBNb3JhbuKAmXMgSSBpbmRpY2F0ZXMgdGhhdCByZXNpZHVhbHMgYXJlIGRpc3RyaWJ1dGVkIHdpdGggc2xpZ2h0IHNwYXRpYWwgZGlzcGVyc2lvbiByYXRoZXIgdGhhbiBjbHVzdGVyaW5nLCBzdWdnZXN0aW5nIHRoZSBzcGF0aWFsIGVycm9yIG1vZGVsIGVmZmVjdGl2ZWx5IGFjY291bnRzIGZvciBtb3N0IHNwYXRpYWwgZGVwZW5kZW5jaWVzIGluIHRoZSBkYXRhLgoKCmBgYHtyIG1vcmFuIEkgb2YgU0UgcmVzaWR1YWxzLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQoKU0VfbW9yYW5NYzwtbW9yYW4ubWMocmVzaWR1YWxzKFNFKSwgcXVlZW5saXN0LDk5OSwgYWx0ZXJuYXRpdmU9InR3by5zaWRlZCIpClNFX21vcmFuTWMKCmBgYAoKQm90aCB0aGUgcmVzaWR1YWwgaGlzdG9ncmFtcyBhcyB3ZWxsIGFzIHRoZSBzY2F0dGVyIHBsb3Qgc3VwcG9ydCB0aGlzIGNvbmNsdXNpb24gaGVyZSBhZ2Fpbi4gVGhlIGhpc3RvZ3JhbSBvZiByZXNpZHVhbHMgaXMgYXBwcm94aW1hdGVseSBub3JtYWxseSBkaXN0cmlidXRlZCwgYW5kIHRoZSBzY2F0dGVyIHBsb3Qgb2YgcmVzaWR1YWxzIGFnYWluc3QgZml0dGVkIHZhbHVlcyBzaG93cyBhIG11Y2ggbGVzcyBldmlkZW50IHRyZW5kIGNvbXBhcmVkIHRvIHRoZSBPTFMgbW9kZWwuIFRoZXJlZm9yZSwgYWxsIG9mIHRoZXNlIHN1Z2dlc3QgdGhhdCB0aGUgc3BhdGlhbCBlcnJvciBtb2RlbCBpcyBhIGdvb2QgZml0IGZvciB0aGUgZGF0YSBjb21wYXJlZCB0byBPTFMuCgpgYGB7ciBtb3JhbiBJIG9mIFNFIHJlc2lkdWFscyBoaXN0b2dyYW0gYW5kIHNjYXR0ZXJwbG90LCBmaWcud2lkdGg9MTAsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CgpwbHQ1IDwtIGdncGxvdChkYXRhLmZyYW1lKHJlcyA9IHJlc2lkdWFscyhTRSkpLCBhZXMoeCA9IHJlcykpICsKICBnZW9tX2hpc3RvZ3JhbShiaW5zID0gMTAwLCBmaWxsID0gIiMyODNkM2IiKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID1TRV9tb3Jhbk1jJHN0YXRpc3RpYywgY29sb3IgPSAiI2M0NDUzNiIsIGxpbmV0eXBlID0gJ2Rhc2hlZCcsIHNpemUgPSAxKSArCiAgbGFicyh0aXRsZSA9ICJPYnNlcnZlZCBhbmQgUGVybXV0ZWQgTW9yYW4ncyBJIG9mIFNFIFJlc2lkdWFscyIsCiAgICAgICBzdWJ0aXRsZSA9ICJPYnNlcnZlZCBNb3JhbidzIEkgaW4gUmVkIiwKICAgICAgIHggPSAiTW9yYW4ncyBJIiwKICAgICAgIHkgPSAiQ291bnQiKSArCiAgdGhlbWVfbGlnaHQoKSArICAgCiAgdGhlbWUocGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gOSxmYWNlID0gIml0YWxpYyIpLAogICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyLCBmYWNlID0gImJvbGQiKSwgCiAgICAgICAgYXhpcy50ZXh0Lng9ZWxlbWVudF90ZXh0KHNpemU9NiksCiAgICAgICAgYXhpcy50ZXh0Lnk9ZWxlbWVudF90ZXh0KHNpemU9NiksIAogICAgICAgIGF4aXMudGl0bGU9ZWxlbWVudF90ZXh0KHNpemU9OCkpCgpwbHQ2IDwtIGdncGxvdChkYXRhID0gZGF0YS5mcmFtZSgKICByZXNpZHVhbHMgPSByZXNpZHVhbHMoU0UpLAogIHNwYXRpYWxfbGFnID0gbGFnLmxpc3R3KHF1ZWVubGlzdCwgcmVzaWR1YWxzKFNFKSkKKSwgYWVzKHggPSByZXNpZHVhbHMsIHkgPSBzcGF0aWFsX2xhZykpICsKICBnZW9tX3BvaW50KGNvbG9yID0gIiMyODNkM2IiLCBhbHBoYSA9IDAuOSwgc2l6ZSA9IDAuNikgKyAgCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgY29sb3IgPSAiI2M0NDUzNiIsIHNlID0gRkFMU0UpICsgCiAgbGFicyh0aXRsZSA9ICJNb3JhbidzIEkgU2NhdHRlciBQbG90IGZvciBTRSBSZXNpZHVhbHMiLAogICAgICAgeCA9ICJMb2dnZWQgTWVkaWFuIEhvdXNlIFZhbHVlIiwKICAgICAgIHkgPSAiU3BhdGlhbCBMYWcgb2YgTE5NRURIVkFMIikgKwogIHRoZW1lX2xpZ2h0KCkgKyAgIAogIHRoZW1lKHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDksZmFjZSA9ICJpdGFsaWMiKSwKICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiwgZmFjZSA9ICJib2xkIiksIAogICAgICAgIGF4aXMudGV4dC54PWVsZW1lbnRfdGV4dChzaXplPTYpLAogICAgICAgIGF4aXMudGV4dC55PWVsZW1lbnRfdGV4dChzaXplPTYpLCAKICAgICAgICBheGlzLnRpdGxlPWVsZW1lbnRfdGV4dChzaXplPTgpKQoKcGx0NSArIHBsdDYKYGBgCgpJdCBzaG91bGQgYmUgbm90ZWQgdGhhdCBoZXJlLCB3ZSBhbHNvIGNvbXBhcmVkIHNwYXRpYWwgbGFnIG1vZGVsIHdpdGggdGhlIHNwYXRpYWwgZXJyb3IgbW9kZWwuIFRoZSBzcGF0aWFsIGxhZyBtb2RlbCBoYXMgYSBsb3dlciBBSUMgKDUyNSkgYW5kIFNDICg1NjQpIHRoYW4gdGhlIHNwYXRpYWwgZXJyb3IgbW9kZWwgKDc1OSBhbmQgNzk4LCByZXNwZWN0aXZlbHkpLCBpbmRpY2F0aW5nIGEgYmV0dGVyIGZpdC4gVGhlIGxvZy1saWtlbGlob29kIG9mIHRoZSBzcGF0aWFsIGxhZyBtb2RlbCAoLTI1NikgaXMgYWxzbyBsZXNzIG5lZ2F0aXZlIHRoYW4gdGhhdCBvZiB0aGUgc3BhdGlhbCBsYWcgZXJyb3IgKC0zNzMpLCBzdWdnZXN0aW5nIHRoYXQgdGhlIHNwYXRpYWwgbGFnIG1vZGVsIGJldHRlciBleHBsYWlucyB0aGUgdmFyaWFiaWxpdHkgaW4gdGhlIGRhdGEuIAoKIyMgR2VvZ3JhcGhpY2FsbHkgV2VpZ2h0ZWQgUmVncmVzc2lvbiBSZXN1bHRzCgpgYGB7ciBjb3ZlcnQgZmlsZSBzdHJ1Y3R1cmUsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGluY2x1ZGU9RkFMU0V9CgpyZWdEYXRhc2hwcyA8LSBhcyhyZWdEYXRhLCAnU3BhdGlhbCcpICAKCmBgYAoKCmBgYHtyIGd3ciwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgZXZhbD1GQUxTRSwgaW5jbHVkZT1GQUxTRX0KCmJ3PC1nd3Iuc2VsKGZvcm11bGE9TE5NRURIVkFMIH4gUENUVkFDQU5UICsgUENUU0lOR0xFUyArIFBDVEJBQ0hNT1IgKyBMTk5CRUxQT1YsIAogICAgICAgICAgICBkYXRhPXJlZ0RhdGFzaHBzLAogICAgICAgICAgICBtZXRob2QgPSAiYWljIiwKICAgICAgICAgICAgYWRhcHQgPSBUUlVFKQpnd3Jtb2RlbDwtZ3dyKGZvcm11bGE9TE5NRURIVkFMIH4gUENUVkFDQU5UICsgUENUU0lOR0xFUyArIFBDVEJBQ0hNT1IgKyBMTk5CRUxQT1YsCiAgICAgICAgICAgICAgZGF0YT1yZWdEYXRhc2hwcywKICAgICAgICAgICAgICBhZGFwdCA9IGJ3LCAjIGFkYXB0aXZlIGJhbmR3aWR0aAogICAgICAgICAgICAgIGd3ZWlnaHQ9Z3dyLkdhdXNzLAogICAgICAgICAgICAgIHNlLmZpdD1UUlVFLCAKICAgICAgICAgICAgICBoYXRtYXRyaXggPSBUUlVFKQpgYGAKCgpgYGB7ciBsb2FkIHByb2Nlc3NlZCBkYXRhLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBpbmNsdWRlPUZBTFNFfQoKYncgPC0gcmVhZFJEUyhoZXJlKCJkYXRhIiwgImJhbmR3aWR0aF9nd3IucmRzIikpCmd3cm1vZGVsIDwtIHJlYWRSRFMoaGVyZSgiZGF0YSIsICJnd3Jtb2RlbC5yZHMiKSkKYGBgCgpUaGUgXChSXjJcKSBmb3IgdGhlIE9MUyByZWdyZXNzaW9uIG1vZGVsIGlzIDAuNjYyLCB3aGlsZSB0aGUgXChSXjJcKSAoUXVhc2ktZ2xvYmFsIFwoUl4yXCkgKSBmb3IgdGhlIEdXUiBtb2RlbCBpcyAwLjg0OC4gVGhlIGhpZ2hlciBcKFJeMlwpIHZhbHVlIG9mIHRoZSBHV1IgbW9kZWwgaW5kaWNhdGVzIHRoYXQgaXQgZG9lcyBhIGJldHRlciBqb2Igb2YgZXhwbGFpbmluZyB0aGUgdmFyaWFuY2UgaW4gdGhlIGRlcGVuZGVudCB2YXJpYWJsZSBcKFx0ZXh0e0xOTUVESFZBTH1cKSBjb21wYXJlZCB0byB0aGUgT0xTIG1vZGVsLiBUaGlzIGltcHJvdmVtZW50IHN1Z2dlc3RzIHRoYXQgdGhlIHNwYXRpYWwgdmFyaWFiaWxpdHkgY2FwdHVyZWQgYnkgdGhlIEdXUiBtb2RlbCBwcm92aWRlcyBhIG1vcmUgYWNjdXJhdGUgcmVwcmVzZW50YXRpb24gb2YgdGhlIHJlbGF0aW9uc2hpcHMgYmV0d2VlbiB0aGUgcHJlZGljdG9ycyBhbmQgdGhlIGRlcGVuZGVudCB2YXJpYWJsZSwgYXMgR1dSIGNhbiBhY2NvdW50IGZvciBzcGF0aWFsIGhldGVyb2dlbmVpdHkgdGhhdCBPTFMgY2Fubm90LgoKQmFzZWQgb24gdGhlIEFrYWlrZSBJbmZvcm1hdGlvbiBDcml0ZXJpb24gKEFJQykgdmFsdWVzLCB0aGUgR1dSIG1vZGVsLCB3aXRoIGFuIEFJQyBvZiAzMDksIGRlbW9uc3RyYXRlcyB0aGUgYmVzdCBmaXQgYW1vbmcgdGhlIG1vZGVscyBjb21wYXJlZC4gVGhlIFNwYXRpYWwgTGFnIG1vZGVsIGhhcyBhIGhpZ2hlciBBSUMgb2YgNTI1LCBmb2xsb3dlZCBieSB0aGUgU3BhdGlhbCBFcnJvciBtb2RlbCBhdCA3NTksIGFuZCB0aGUgT0xTIHJlZ3Jlc3Npb24gbW9kZWwgYXQgMTQzNS4gU2luY2UgYSBsb3dlciBBSUMgaW5kaWNhdGVzIGEgYmV0dGVyIGZpdCwgdGhlIEdXUiBtb2RlbCBhcHBlYXJzIHRvIGJlIHRoZSBtb3N0IGVmZmVjdGl2ZSBpbiBleHBsYWluaW5nIHRoZSB2YXJpYW5jZSBpbiB0aGUgZGF0YS4gVGhpcyBzdWdnZXN0cyB0aGF0IEdXUiwgd2hpY2ggYWNjb3VudHMgZm9yIHNwYXRpYWwgaGV0ZXJvZ2VuZWl0eSBieSBhbGxvd2luZyBtb2RlbCBjb2VmZmljaWVudHMgdG8gdmFyeSBhY3Jvc3MgbG9jYXRpb25zLCBwcm92aWRlcyBhIG1vcmUgYWNjdXJhdGUgYW5kIHJvYnVzdCBmaXQgZm9yIHRoaXMgZGF0YXNldCB0aGFuIHRoZSBvdGhlciBtb2RlbHMuCgoKYGBge3IgcHJlc2VudCBnd3IgcmVzdWx0cywgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KZ3dybW9kZWwKYGBgCgpUaGUgY2hvcm9wbGV0aCBtYXAgb2YgbG9jYWwgXCggUl4yIFwpIHZhbHVlcyBmcm9tIHRoZSBHV1IgbW9kZWwgaWxsdXN0cmF0ZXMgaG93IHRoZSBtb2RlbCBleHBsYWlucyB2YXJpYXRpb25zIGluIGxvZ2dlZCBtZWRpYW4gaG91c2UgdmFsdWVzIGFjcm9zcyB0aGUgY2l0eS4gRGFya2VyLWNvbG9yZWQgYXJlYXMsIHN1Y2ggYXMgdGhlIG5vcnRod2VzdGVybiwgcGFydHMgb2YgdGhlIG5vcnRoZWFzdGVybiwgYW5kIGZhciB3ZXN0ZXJuIHJlZ2lvbnMsIGluZGljYXRlIGEgc3Ryb25nZXIgbW9kZWwgZml0LCB3aGVyZSB0aGUgcHJlZGljdG9ycyBpbiB0aGUgbW9kZWwgZXhwbGFpbiBhIGxhcmdlciBwcm9wb3J0aW9uIG9mIHRoZSB2YXJpYWJpbGl0eSBpbiBob3VzZSB2YWx1ZXMuIEluIGNvbnRyYXN0LCBsaWdodGVyLWNvbG9yZWQgYXJlYXMsIHBhcnRpY3VsYXJseSBpbiB0aGUgbm9ydGhlcm4gYW5kIHdlc3Rlcm4gcGFydHMgb2YgdGhlIGNpdHksIHNob3cgYSB3ZWFrZXIgbW9kZWwgZml0LCBzdWdnZXN0aW5nIHRoYXQgdGhlIHByZWRpY3RvcnMgYXJlIGxlc3MgZWZmZWN0aXZlIGluIGNhcHR1cmluZyB0aGUgdmFyaWFiaWxpdHkgaW4gdGhlc2UgcmVnaW9ucy4gCgpgYGB7ciBsb2NhbCBSLXNxdWFyZXMgY2hvcm9wbGV0aCwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KCmd3cnJlc3VsdHM8LWFzLmRhdGEuZnJhbWUoZ3dybW9kZWwkU0RGKQpyZWdEYXRhc2hwcyRsb2NhbFIyPC1nd3JyZXN1bHRzJGxvY2FsUjIKcmVnRGF0YXNocHNfc2YgPC0gc3RfYXNfc2YocmVnRGF0YXNocHMpCmdncGxvdChkYXRhID0gcmVnRGF0YXNocHNfc2YpICsKICBnZW9tX3NmKGFlcyhmaWxsID0gbG9jYWxSMiksIGNvbG9yID0gTkEpICsgIAogIHNjYWxlX2ZpbGxfZ3JhZGllbnRuKGNvbG9ycyA9IGMoIiNGQUY5RjYiLCAiI2M0NDUzNiIpLCAKICAgICAgICAgICAgICAgICAgICAgICBuYW1lID0gIkxvY2FsIFItU3F1YXJlZCIsIAogICAgICAgICAgICAgICAgICAgICAgIG5hLnZhbHVlID0gInRyYW5zcGFyZW50IikrCiAgbGFicyh0aXRsZSA9ICJMb2NhbCBSLVNxdWFyZWQgZnJvbSBHV1IiLCB4ID0gIiIsIHkgPSAiIikgKyAKICAgdGhlbWUobGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDkpLAogICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApLAogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGlja3MueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRpY2tzLnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgcGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gOSwgZmFjZSA9ICJpdGFsaWMiKSwKICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiwgZmFjZSA9ICJib2xkIiksCiAgICAgICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gImdyZXkiLCBmaWxsID0gTkEsIHNpemUgPSAwLjgpKQoKYGBgCgpUaGUgYW5hbHlzaXMgaW5kaWNhdGVzIHRoYXQgdGhlIEdXUiBtb2RlbCBoYXMgc3VjY2Vzc2Z1bGx5IHJlZHVjZWQgc3BhdGlhbCBhdXRvY29ycmVsYXRpb24gaW4gdGhlIHJlc2lkdWFscyBjb21wYXJlZCB0byB0aGUgT0xTIG1vZGVsLiBJbiB0aGUgZGlzdHJpYnV0aW9uIG9mIE1vcmFu4oCZcyBJIHZhbHVlcyBmb3IgR1dSIHJlc2lkdWFscywgdGhlIG9ic2VydmVkIE1vcmFu4oCZcyBJIGlzIGNsb3NlIHRvIHplcm8sIHN1Z2dlc3RpbmcgbWluaW1hbCBzcGF0aWFsIGF1dG9jb3JyZWxhdGlvbiBhbmQgYWxpZ25pbmcgd2l0aCB0aGUgYXNzdW1wdGlvbiBvZiB1bmNvcnJlbGF0ZWQgcmVzaWR1YWxzLiBJbiBjb250cmFzdCwgdGhlIE1vcmFu4oCZcyBJIGZvciB0aGUgT0xTIHJlc2lkdWFscyBpcyBib3RoIHBvc2l0aXZlIGFuZCBzdGF0aXN0aWNhbGx5IHNpZ25pZmljYW50LCBpbmRpY2F0aW5nIGEgc3Ryb25nZXIgZGVncmVlIG9mIHNwYXRpYWwgZGVwZW5kZW5jZS4gCgpUaGUgc3BhdGlhbCBsYWcgbW9kZWwgYWxzbyByZWR1Y2VzIHNwYXRpYWwgYXV0b2NvcnJlbGF0aW9uIGluIHRoZSByZXNpZHVhbHMsIGFsdGhvdWdoIG5vdCBhcyBlZmZlY3RpdmVseSBhcyB0aGUgR1dSIG1vZGVsLiBUaGUgc3BhdGlhbCBlcnJvciBtb2RlbCBwZXJmb3JtcyBzaW1pbGFybHksIGJ1dCB0aGUgcmVzaWR1YWxzIGV4aGliaXQgc2xpZ2h0bHkgbW9yZSBzcGF0aWFsIGF1dG9jb3JyZWxhdGlvbiB0aGFuIHRob3NlIG9mIHRoZSBHV1IgbW9kZWwuIE92ZXJhbGwsIHRoZXNlIHJlc3VsdHMgc3VnZ2VzdCB0aGF0IHRoZSBHV1IgbW9kZWwgcHJvdmlkZXMgdGhlIGJlc3QgZml0IGluIHRlcm1zIG9mIG1pbmltaXppbmcgc3BhdGlhbCBhdXRvY29ycmVsYXRpb24sIGNhcHR1cmluZyBsb2NhbCBzcGF0aWFsIHZhcmlhdGlvbnMgbW9yZSBwcmVjaXNlbHkgdGhhbiB0aGUgc3BhdGlhbCBsYWcgYW5kIHNwYXRpYWwgZXJyb3IgbW9kZWxzLiBUaGlzIGluZGljYXRlcyB0aGF0IEdXUiBpcyBwYXJ0aWN1bGFybHkgZWZmZWN0aXZlIGZvciBtb2RlbGluZyBzcGF0aWFsIGhldGVyb2dlbmVpdHkgaW4gdGhpcyBkYXRhc2V0LgoKYGBge3IgbW9yYW4gSSBvZiBnd3IgcmVzaWR1YWxzLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQoKR1dSX21vcmFuTWM8LW1vcmFuLm1jKGd3cnJlc3VsdHMkZ3dyLmUsIHF1ZWVubGlzdCwgOTk5LCBhbHRlcm5hdGl2ZT0idHdvLnNpZGVkIikKR1dSX21vcmFuTWMKCmBgYAoKVGhlIE1vcmFuJ3MgSSBzY2F0dGVyIHBsb3QgZm9yIHRoZSBHV1IgcmVzaWR1YWxzIHNob3dzIG1pbmltYWwgc3BhdGlhbCBhdXRvY29ycmVsYXRpb24sIGFzIGluZGljYXRlZCBieSB0aGUgbmVhcmx5IGhvcml6b250YWwgdHJlbmQgb2YgdGhlIGxpbmUsIHN1Z2dlc3RpbmcgdGhhdCB0aGUgR1dSIG1vZGVsIGhhcyBzdWNjZXNzZnVsbHkgYWRkcmVzc2VkIG11Y2ggb2YgdGhlIHNwYXRpYWwgZGVwZW5kZW5jeSBwcmVzZW50IGluIHRoZSBkYXRhLiBUaGlzIGlzIGNvbnNpc3RlbnQgd2l0aCB0aGUgZWFybGllciBoaXN0b2dyYW0gcmVzdWx0cywgd2hlcmUgdGhlIE1vcmFuJ3MgSSB2YWx1ZSBmb3IgR1dSIHJlc2lkdWFscyB3YXMgY2xvc2UgdG8gemVybywgZnVydGhlciBhZmZpcm1pbmcgdGhhdCB0aGUgbW9kZWwgZWZmZWN0aXZlbHkgY2FwdHVyZXMgbG9jYWwgc3BhdGlhbCB2YXJpYXRpb25zIGluIGxvZ2dlZCBtZWRpYW4gaG91c2UgdmFsdWVzLiAKCmBgYHtyIG1vcmFuIEkgb2YgZ3dyIHJlc2lkdWFscyBoaXN0b2dyYW0gYW5kIHNjYXR0ZXJwbG90LCBmaWcud2lkdGg9MTAsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CgpwbHQ3IDwtIGdncGxvdChkYXRhLmZyYW1lKHJlcyA9IGd3cnJlc3VsdHMkZ3dyLmUpLCBhZXMoeCA9IHJlcykpICsKICBnZW9tX2hpc3RvZ3JhbShiaW5zID0gMTAwLCBmaWxsID0gIiMyODNkM2IiKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID1HV1JfbW9yYW5NYyRzdGF0aXN0aWMsIGNvbG9yID0gIiNjNDQ1MzYiLCBsaW5ldHlwZSA9ICdkYXNoZWQnLCBzaXplID0gMSkgKwogIGxhYnModGl0bGUgPSAiT2JzZXJ2ZWQgYW5kIFBlcm11dGVkIE1vcmFuJ3MgSSBvZiBHV1IgUmVzaWR1YWxzIiwKICAgICAgIHN1YnRpdGxlID0gIk9ic2VydmVkIE1vcmFuJ3MgSSBpbiBSZWQiLAogICAgICAgeCA9ICJNb3JhbidzIEkiLAogICAgICAgeSA9ICJDb3VudCIpICsKICB0aGVtZV9saWdodCgpICsgICAKICB0aGVtZShwbG90LnN1YnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSA5LGZhY2UgPSAiaXRhbGljIiksCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIsIGZhY2UgPSAiYm9sZCIpLCAKICAgICAgICBheGlzLnRleHQueD1lbGVtZW50X3RleHQoc2l6ZT02KSwKICAgICAgICBheGlzLnRleHQueT1lbGVtZW50X3RleHQoc2l6ZT02KSwgCiAgICAgICAgYXhpcy50aXRsZT1lbGVtZW50X3RleHQoc2l6ZT04KSkKCnBsdDggPC0gZ2dwbG90KGRhdGEgPSBkYXRhLmZyYW1lKAogIHJlc2lkdWFscyA9IGd3cnJlc3VsdHMkZ3dyLmUsCiAgc3BhdGlhbF9sYWcgPSBsYWcubGlzdHcocXVlZW5saXN0LCBnd3JyZXN1bHRzJGd3ci5lKQopLCBhZXMoeCA9IHJlc2lkdWFscywgeSA9IHNwYXRpYWxfbGFnKSkgKwogIGdlb21fcG9pbnQoY29sb3IgPSAiIzI4M2QzYiIsIGFscGhhID0gMC45LCBzaXplID0gMC42KSArICAKICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBjb2xvciA9ICIjYzQ0NTM2Iiwgc2UgPSBGQUxTRSkgKyAKICBsYWJzKHRpdGxlID0gIk1vcmFuJ3MgSSBTY2F0dGVyIFBsb3QgZm9yIEdXUiBSZXNpZHVhbHMiLAogICAgICAgeCA9ICJMb2dnZWQgTWVkaWFuIEhvdXNlIFZhbHVlIiwKICAgICAgIHkgPSAiU3BhdGlhbCBMYWcgb2YgTE5NRURIVkFMIikgKwogIHRoZW1lX2xpZ2h0KCkgKyAgIAogIHRoZW1lKHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDksZmFjZSA9ICJpdGFsaWMiKSwKICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiwgZmFjZSA9ICJib2xkIiksIAogICAgICAgIGF4aXMudGV4dC54PWVsZW1lbnRfdGV4dChzaXplPTYpLAogICAgICAgIGF4aXMudGV4dC55PWVsZW1lbnRfdGV4dChzaXplPTYpLCAKICAgICAgICBheGlzLnRpdGxlPWVsZW1lbnRfdGV4dChzaXplPTgpKQoKcGx0NyArIHBsdDgKYGBgCgpMb29raW5nIGF0IGVhY2ggcHJlZGljdG9ycyBpbiBkZXRhaWwsIHRoZSB2YWNhbmN5IHJhdGUgZ2VuZXJhbGx5IGhhcyBhIG5lZ2F0aXZlIGltcGFjdCBvbiBob3VzaW5nIHZhbHVlcywgd2l0aCBzaWduaWZpY2FudCBuZWdhdGl2ZSBlZmZlY3RzIG9ic2VydmVkIGluIENlbnRlciBDaXR5LCBub3J0aHdlc3Rlcm4gYXJlYXMsIHBhcnRzIG9mIHRoZSBub3J0aGVhc3Rlcm4gcmVnaW9uLCBhbmQgdGhlIHdlc3Rlcm4gcGFydCBvZiB0aGUgY2l0eS4gSG93ZXZlciwgdGhlcmUgaXMgYSBsb2NhbGl6ZWQgYXJlYSBpbiBzb3V0aGVybiBDZW50ZXIgQ2l0eSB3aGVyZSB2YWNhbmN5IHJhdGVzIHVuZXhwZWN0ZWRseSBoYXZlIGEgcG9zaXRpdmUgaW1wYWN0IG9uIGhvdXNpbmcgdmFsdWVzLgoKU2luZ2xlLWZhbWlseSBob3VzaW5nLCBpbiBnZW5lcmFsLCBwb3NpdGl2ZWx5IGltcGFjdHMgaG91c2luZyB2YWx1ZXMsIHBhcnRpY3VsYXJseSBpbiB0aGUgZmFyIG5vcnRoZWFzdCBhbmQgZmFyIG5vcnRod2VzdCBhcmVhcywgd2hlcmUgdGhpcyBlZmZlY3QgaXMgbW9yZSBwcm9ub3VuY2VkLiBDb252ZXJzZWx5LCBpbiBzb21lIHBhcnRzIG9mIHRoZSBjaXR54oCUc3VjaCBhcyBlYXN0ZXJuIFBoaWxhZGVscGhpYSwgcGFydHMgb2YgdGhlIHdlc3QsIGFuZCBzZWN0aW9ucyBvZiB0aGUgc291dGjigJR0aGUgaW1wYWN0IG9mIHNpbmdsZS1mYW1pbHkgaG91c2luZyBpcyBuZWdhdGl2ZSBhbmQgc3RhdGlzdGljYWxseSBzaWduaWZpY2FudC4KClRoZSBwZXJjZW50YWdlIG9mIHJlc2lkZW50cyB3aXRoIGEgYmFjaGVsb3LigJlzIGRlZ3JlZSBnZW5lcmFsbHkgaGFzIGEgcG9zaXRpdmUgaW1wYWN0IG9uIGhvdXNpbmcgdmFsdWVzLCB3aXRoIG5vIGFyZWFzIHNob3dpbmcgYSBuZWdhdGl2ZSByZWxhdGlvbnNoaXAgYWNyb3NzIHRoZSBjaXR5LiBUaGlzIHBvc2l0aXZlIGluZmx1ZW5jZSBpcyBlc3BlY2lhbGx5IHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQgaW4gdGhlIG5vcnRoZXJuIGFuZCBub3J0aGVhc3Rlcm4gcGFydHMgb2YgdGhlIGNpdHkuCgpGaW5hbGx5LCB0aGUgcG92ZXJ0eSByYXRlIGdlbmVyYWxseSBoYXMgYSBuZWdhdGl2ZSBlZmZlY3Qgb24gaG91c2luZyB2YWx1ZXMuIFRoaXMgZWZmZWN0IGlzIG1vcmUgc3RhdGlzdGljYWxseSBzaWduaWZpY2FudCBpbiB0aGUgc291dGhlcm4sIGVhc3Rlcm4sIGFuZCBub3J0aHdlc3Rlcm4gcGFydHMgb2YgdGhlIGNpdHkuIAoKT3ZlcmFsbCwgdGhlc2Ugc3BhdGlhbCB2YXJpYXRpb25zIGhpZ2hsaWdodCBob3cgZGlmZmVyZW50IGZhY3RvcnMgYWZmZWN0IGhvdXNpbmcgdmFsdWVzIHVuaXF1ZWx5IGFjcm9zcyBQaGlsYWRlbHBoaWEsIGVtcGhhc2l6aW5nIHRoZSBpbXBvcnRhbmNlIG9mIGxvY2FsaXplZCBhbmFseXNpcyBpbiB1bmRlcnN0YW5kaW5nIHByb3BlcnR5IGR5bmFtaWNzLgoKYGBge3IgcmF0aW8gb2YgY29lZmZpY2llbnRzIHRvIHN0YW5kYXJkIGVycm9yLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBpbmNsdWRlPUZBTFNFfQoKcmVnRGF0YXNocHNfc2YkY29lZlBDVFZBQ0FOVHN0PC1nd3JyZXN1bHRzJFBDVFZBQ0FOVC9nd3JyZXN1bHRzJFBDVFZBQ0FOVF9zZQpyZWdEYXRhc2hwc19zZiRjb2VmUENUU0lOR0xFU3N0PC1nd3JyZXN1bHRzJFBDVFNJTkdMRVMvZ3dycmVzdWx0cyRQQ1RTSU5HTEVTX3NlCnJlZ0RhdGFzaHBzX3NmJGNvZWZQQ1RCQUNITU9Sc3Q8LWd3cnJlc3VsdHMkUENUQkFDSE1PUi9nd3JyZXN1bHRzJFBDVEJBQ0hNT1Jfc2UKcmVnRGF0YXNocHNfc2YkY29lZkxOTkJFTFBPVnN0PC1nd3JyZXN1bHRzJExOTkJFTFBPVi9nd3JyZXN1bHRzJExOTkJFTFBPVl9zZQoKYGBgCgoKYGBge3IgcmF0aW8gb2YgY29lZmZpY2llbnRzIHRvIHN0YW5kYXJkIGVycm9yIHBsb3QsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD0xMH0KCnJlZ0RhdGFzaHBzX3NmJGNvZWZQQ1RWQUNBTlRzdF9jYXQgPC0gY3V0KHJlZ0RhdGFzaHBzX3NmJGNvZWZQQ1RWQUNBTlRzdCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWtzID0gYygtSW5mLCAtMiwgMCwgMiwgSW5mKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygiPCAtMiIsICItMiB0byAwIiwgIjAgdG8gMiIsICI+IDIiKSkKcmVnRGF0YXNocHNfc2YkY29lZlBDVFNJTkdMRVNzdF9jYXQgPC0gY3V0KHJlZ0RhdGFzaHBzX3NmJGNvZWZQQ1RTSU5HTEVTc3QsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IGMoLUluZiwgLTIsIDAsIDIsIEluZiksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIjwgLTIiLCAiLTIgdG8gMCIsICIwIHRvIDIiLCAiPiAyIikpCgpyZWdEYXRhc2hwc19zZiRjb2VmUENUQkFDSE1PUnN0X2NhdCA8LSBjdXQocmVnRGF0YXNocHNfc2YkY29lZlBDVEJBQ0hNT1JzdCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBicmVha3MgPSBjKC1JbmYsIC0yLCAwLCAyLCBJbmYpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCI8IC0yIiwgIi0yIHRvIDAiLCAiMCB0byAyIiwgIj4gMiIpKQoKcmVnRGF0YXNocHNfc2YkY29lZkxOTkJFTFBPVnN0X2NhdCA8LSBjdXQocmVnRGF0YXNocHNfc2YkY29lZkxOTkJFTFBPVnN0LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IGMoLUluZiwgLTIsIDAsIDIsIEluZiksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIjwgLTIiLCAiLTIgdG8gMCIsICIwIHRvIDIiLCAiPiAyIikpCgoKcDEgPC0gZ2dwbG90KHJlZ0RhdGFzaHBzX3NmKSArCiAgICBnZW9tX3NmKGFlcyhmaWxsID0gY29lZlBDVFZBQ0FOVHN0X2NhdCksIGNvbG9yID0gTkEpICsgIAogICAgc2NhbGVfZmlsbF9tYW51YWwoCiAgICAgIHZhbHVlcyA9IGMoIiNjNDQ1MzYiLCAiI2YxYjFhNiIsICIjOGZhN2E1IiwgIiMyODNkM2IiKSwgCiAgICAgIG5hbWUgPSAiUmF0aW8gQ2F0ZWdvcnkiICAKICAgICkgKwogICBsYWJzKHRpdGxlID0gIlBDVFZBQ0FOVCBDb2VmZmljaWVudCB0byBTdGFuZGFyZCBFcnJvciIsCiAgICAgICB4ID0gIiIsIHkgPSAiIikgKwogICB0aGVtZShsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gOSksCiAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCksCiAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50aWNrcy54ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGlja3MueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBwbG90LnN1YnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSA5LCBmYWNlID0gIml0YWxpYyIpLAogICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyLCBmYWNlID0gImJvbGQiKSwKICAgICAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSAiZ3JleSIsIGZpbGwgPSBOQSwgc2l6ZSA9IDAuOCkpCgpwMiA8LSBnZ3Bsb3QocmVnRGF0YXNocHNfc2YpICsKICAgIGdlb21fc2YoYWVzKGZpbGwgPSBjb2VmUENUU0lOR0xFU3N0X2NhdCksIGNvbG9yID0gTkEpICsgIAogICAgc2NhbGVfZmlsbF9tYW51YWwoCiAgICAgIHZhbHVlcyA9IGMoIiNjNDQ1MzYiLCAiI2YxYjFhNiIsICIjOGZhN2E1IiwgIiMyODNkM2IiKSwgCiAgICAgIG5hbWUgPSAiUmF0aW8gQ2F0ZWdvcnkiICAKICAgICkgKwogICBsYWJzKHRpdGxlID0gIlBDVFNJTkdMRVMgQ29lZmZpY2llbnQgdG8gU3RhbmRhcmQgRXJyb3IiLAogICAgICAgeCA9ICIiLCB5ID0gIiIpICsKICAgdGhlbWUobGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDkpLAogICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApLAogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGlja3MueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRpY2tzLnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgcGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gOSwgZmFjZSA9ICJpdGFsaWMiKSwKICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiwgZmFjZSA9ICJib2xkIiksCiAgICAgICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gImdyZXkiLCBmaWxsID0gTkEsIHNpemUgPSAwLjgpKQoKCnAzIDwtIGdncGxvdChyZWdEYXRhc2hwc19zZikgKwogICAgZ2VvbV9zZihhZXMoZmlsbCA9IGNvZWZQQ1RCQUNITU9Sc3RfY2F0KSwgY29sb3IgPSBOQSkgKyAgCiAgICBzY2FsZV9maWxsX21hbnVhbCgKICAgICAgdmFsdWVzID0gYygiI2M0NDUzNiIsICIjZjFiMWE2IiwgIiM4ZmE3YTUiLCAiIzI4M2QzYiIpLCAKICAgICAgbmFtZSA9ICJSYXRpbyBDYXRlZ29yeSIgIAogICAgKSArCiAgIGxhYnModGl0bGUgPSAiUENUQkFDSE1PUiBDb2VmZmljaWVudCB0byBTdGFuZGFyZCBFcnJvciIsCiAgICAgICB4ID0gIiIsIHkgPSAiIikgKwogICB0aGVtZShsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gOSksCiAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCksCiAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50aWNrcy54ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGlja3MueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBwbG90LnN1YnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSA5LCBmYWNlID0gIml0YWxpYyIpLAogICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyLCBmYWNlID0gImJvbGQiKSwKICAgICAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSAiZ3JleSIsIGZpbGwgPSBOQSwgc2l6ZSA9IDAuOCkpCgpwNCA8LSBnZ3Bsb3QocmVnRGF0YXNocHNfc2YpICsKICAgIGdlb21fc2YoYWVzKGZpbGwgPSBjb2VmTE5OQkVMUE9Wc3RfY2F0KSwgY29sb3IgPSBOQSkgKyAgCiAgICBzY2FsZV9maWxsX21hbnVhbCgKICAgICAgdmFsdWVzID0gYygiI2M0NDUzNiIsICIjZjFiMWE2IiwgIiM4ZmE3YTUiLCAiIzI4M2QzYiIpLCAKICAgICAgbmFtZSA9ICJSYXRpbyBDYXRlZ29yeSIgIAogICAgKSArCiAgIGxhYnModGl0bGUgPSAiTE5OQkVMUE9WIENvZWZmaWNpZW50IHRvIFN0YW5kYXJkIEVycm9yIiwKICAgICAgIHggPSAiIiwgeSA9ICIiKSArCiAgIHRoZW1lKGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSA5KSwKICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwKSwKICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRpY2tzLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50aWNrcy55ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDksIGZhY2UgPSAiaXRhbGljIiksCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIsIGZhY2UgPSAiYm9sZCIpLAogICAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9yZWN0KGNvbG91ciA9ICJncmV5IiwgZmlsbCA9IE5BLCBzaXplID0gMC44KSkKCnAxICsgcDIgKyBwMyArIHA0ICsgCiAgcGxvdF9sYXlvdXQobmNvbCA9IDIpCmBgYAoKIyBEaXNjdXNzaW9uCgpJbiB0aGlzIHJlcG9ydCwgd2UgY29uZHVjdGVkIGEgY29tcGFyYXRpdmUgYW5hbHlzaXMgb2YgZm91ciByZWdyZXNzaW9uIG1ldGhvZHPigJRPcmRpbmFyeSBMZWFzdCBTcXVhcmVzIChPTFMpLCBTcGF0aWFsIExhZywgU3BhdGlhbCBFcnJvciwgYW5kIEdlb2dyYXBoaWNhbGx5IFdlaWdodGVkIFJlZ3Jlc3Npb24gKEdXUinigJR0byBldmFsdWF0ZSB0aGVpciBlZmZlY3RpdmVuZXNzIGluIGV4cGxhaW5pbmcgdGhlIHZhcmlhbmNlIGluIHRoZSBkZXBlbmRlbnQgdmFyaWFibGUsIFwoXHRleHR7TE5NRURIVkFMfVwpLiBPdXIgZmluZGluZ3MgaW5kaWNhdGUgdGhhdCB0aGUgR1dSIG1vZGVsIGV4aGliaXRlZCB0aGUgaGlnaGVzdCBleHBsYW5hdG9yeSBwb3dlciwgd2l0aCBhIHF1YXNpLWdsb2JhbCBcKFJeMlwpIG9mIDAuODQsIGNvbXBhcmVkIHRvIHRoZSBPTFMgXChSXjJcKSBvZiAwLjY2Miwgc3VnZ2VzdGluZyB0aGF0IEdXUiBpcyBiZXR0ZXIgc3VpdGVkIHRvIGNhcHR1cmUgbG9jYWwgdmFyaWF0aW9ucyBpbiB0aGUgZGF0YS4KClRoZSBBa2Fpa2UgSW5mb3JtYXRpb24gQ3JpdGVyaW9uIChBSUMpIGZ1cnRoZXIgc3VwcG9ydHMgdGhlIHN1aXRhYmlsaXR5IG9mIEdXUiwgd2hpY2ggYWNoaWV2ZWQgYW4gQUlDIG9mIDMwOSwgaW4gY29udHJhc3QgdG8gdGhlIE9MUyBBSUMgb2YgMTQzNSwgdGhlIFNwYXRpYWwgTGFnIEFJQyBvZiA1MjUsIGFuZCB0aGUgU3BhdGlhbCBFcnJvciBBSUMgb2YgNzU5LiBOZXZlcnRoZWxlc3MsIHRoZSBsb3dlciBBSUMgdmFsdWVzIGluIHNwYXRpYWwgbGFnIGFuZCBzcGF0aWFsIGVycm9yIHJlZ3Jlc3Npb24gc3RpbGwgaW5kaWNhdGUgdGhhdCBib3RoIG1vZGVscyBwcm92aWRlIGFyZSBtdWNoIGJldHRlciBmaXQgdGhhbiB0aGUgT0xTIG1vZGVsLCBlc3BlY2lhbGx5IHRoZSBzcGF0aWFsIGxhZyBtb2RlbC4gQW5vdGhlciBvYnNlcnZhdGlvbiBpcyB0aGUgcmVkdWN0aW9uIGluIHRoZSBjb2VmZmljaWVudCBtYWduaXR1ZGVzIGZvciB0aGUgcHJlZGljdG9ycyBpbiB0aGUgc3BhdGlhbCBsYWcgYW5kIHNwYXRpYWwgZXJyb3IgbW9kZWxzIGNvbXBhcmVkIHRvIE9MUywgc3VnZ2VzdGluZyB0aGF0IHRoZXkgcHJvdmlkZSBtb3JlIGNvbnNlcnZhdGl2ZSBlc3RpbWF0ZXMgb2YgdGhlIHByZWRpY3RvcnMnIGVmZmVjdHMgb24gbWVkaWFuIGhvbWUgdmFsdWVzIGZvciBhY2NvdW50aW5nIHNwYXRpYWwgYXV0b2NvcnJlbGF0aW9uLiBZZXQsIG92ZXJhbGwsIG91ciBhbmFseXNpcyBkZW1vbnN0cmF0ZXMgdGhhdCB0aGUgR1dSIG1ldGhvZCBpcyB0aGUgbW9zdCBlZmZlY3RpdmUgZm9yIHRoaXMgZGF0YXNldC4gCgpXaGlsZSBHV1Igb2ZmZXJzIHNldmVyYWwgYWR2YW50YWdlcywgc3VjaCBhcyBjYXB0dXJpbmcgc3BhdGlhbCBoZXRlcm9nZW5laXR5IGFuZCBwcm92aWRpbmcgbG9jYWxpemVkIGluc2lnaHRzLCBpdCBhbHNvIGhhcyBsaW1pdGF0aW9ucywgd2hpY2ggaXMgd2h5IGEgbG90IG9mIHNwYXRpYWwgc3RhdGlzdGljaWFucyB1c2UgaXQgb25seSBmb3IgZGF0YSBleHBsb3JhdGlvbiByYXRoZXIgdGhhbiBmb3IgbW9kZWxpbmcuIE1vc3Qgbm90YWJseSwgYSBsb3Qgb2YgYXNzdW1wdGlvbnMgd2UgaGF2ZSBpbiBPTFMgc3RpbGwgaG9sZCBpbiBHV1IsIHN1Y2ggYXMgbGluZWFyaXR5LCBob21vc2NlZGFzdGljaXR5LCBhbmQgbm9ybWFsaXR5IG9mIGVycm9ycy4gQXMgYW4gZXhhbXBsZSwgZnJvbSBvdXIgcHJldmlvdXMgYXNzaWdubWVudCwgd2Uga25vdyB0aGF0IHRoZXJlJ3MgbXVsdGljb2xsaW5lYXJpdHkgYmV0d2VlbiBwcmVkaWN0b3JzIC0gaGlnaGVyIGVkdWNhdGlvbiBhdHRhaW5tZW50IGlzIGNsZWFybHkgYXNzb2NpYXRlZCB3aXRoIGxvd2VyIHBvdmVydHkgbGV2ZWwuIEFzIHN1Y2gsIG91ciBjdXJyZW50IEdXUiBtb2RlbCBjbGVhcmx5IGRvZXMgbm90IGFjY291bnQgZm9yIHRoYXQuIFdlIGFsc28ga25vdyB0aGF0IHNvbWUgb2Ygb3VyIHByZWRpY3RvciB2YXJpYWJsZXMsIHN1Y2ggYXMgXChcdGV4dHtQQ1RTSU5HTEVTfVwpIGFuZCBcKFx0ZXh0e1BDVEJBQ0hNT1J9XCkgYXJlIG5vdCBub3JtYWxseSBkaXN0cmlidXRlZCwgd2hpY2ggdmlvbGF0ZXMgdGhlIGFzc3VtcHRpb24uIAoKT3RoZXIgdGhhbiB0aGF0LCBHV1IgcmVxdWlyZXMgYXQgbGVhc3QgMzAwIG9ic2VydmF0aW9ucyBhbmQgdXNlcidzIGNob2ljZSBvZiBiYW5kd2lkdGggY2FuIHNpZ25pZmljYW50bHkgYWZmZWN0IHJlc3VsdHMuIEluIG91ciBleGFtcGxlIHdlIGhhdmUgd2F5IG1vcmUgdGhhbiAzMDAgb2JzZXJ2YXRpb25zIGFuZCBSIGF1dG9tYXRpY2FsbHkgcGlja2VkIHRoZSBiYW5kd2lkdGhzIGZvciB1cywgc3RpbGwgd2Ugc2hvdWxkIGJlIGNhdXRpb3VzIGFib3V0IHRoZSByZXN1bHRzLgoKV2UgYWxzbyBuZWVkIHRvIGJlIGNhcmVmdWwgYWJvdXQgdGhlIHRoZSB1c2Ugb2YgdGVybSBiZXR3ZWVuICoqc3BhdGlhbGx5IGxhZ2dlZCByZXNpZHVhbHMqKiBhbmQgKipzcGF0aWFsIGxhZyBtb2RlbCByZXNpZHVhbHMqKi4gVGhlIGZvcm1lciB0ZXJtLCAqKnNwYXRpYWxseSBsYWdnZWQgcmVzaWR1YWxzKiosIHJlZmVycyB0byBhIHNlcmllcyBvZiByZXNpZHVhbHMgdGhhdCB0YWtlIGludG8gYWNjb3VudCB0aGUgaW5mbHVlbmNlIG9mIG5lYXJieSBvYnNlcnZhdGlvbnMgdGhyb3VnaCBhIHdlaWdodGluZyBzY2hlbWUuIFRoZSBsYXR0ZXIgdGVybSwgKipzcGF0aWFsIGxhZyBtb2RlbCByZXNpZHVhbHMqKiByZWZlcnMgdG8gdGhlIGVycm9yIHRlcm1zIGZyb20gdGhlIHJlc3VsdCBvZiBhIG1vZGVsIHRoYXQgaW5jb3Jwb3JhdGVzIGEgc3BhdGlhbCBsYWcgdGVybSAod2hpY2ggaXMgdGhlIHZhbHVlcyBvZiB0aGUgZGVwZW5kZW50IHZhcmlhYmxlIGZyb20gbmVpZ2hib3Jpbmcgb2JzZXJ2YXRpb25zKS4gCgpBbmQgbGFzdGx5LCB3ZSB3b3VsZCBsaWtlIHRvIGhpZ2hsaWdodCBzb21lIGxpbWl0YXRpb25zIG9mIHVzaW5nIEFyY0dJUyBmb3IgR1dSLiBUaGUgbWFqb3IgaXNzdWVzIGlzIHRoYXQgQXJjR0lTIGRvZXMgbm90IGFsd2F5cyBhbGxvdyBmb3IgdGhlIHNhbWUgbGV2ZWwgb2YgZmxleGliaWxpdHkgaW4gc2VsZWN0aW5nIGJhbmR3aWR0aCBtZXRob2RzIG9yIGtlcm5lbCBmdW5jdGlvbnMgYXMgUiwgYW5kIGl0IGhhcyBhIHZlcnkgZGlmZmVyZW50IGFuZCB2ZXJ5IGNvbmZ1c2luZyB3YXkgb2Ygb3B0aW1pemluZyBiYW5kd2lkdGguIEluIGFkZGl0aW9uLCBBcmNHSVMgUHJvIGRvZXMgbm90IGdpdmUgQUlDLCBqdXN0IEFJQ2MsIHdoaWNoIG1ha2VzIGl0IGRpZmZpY3VsdCB0byBjb21wYXJlIEdXUiBvdXRwdXQgdG8gb3RoZXIgbW9kZWxzLiBNb3JlIGltcG9ydGFudGx5LCBpbiB0aGUgY3VycmVudCBhbmQgZWFybGllciB2ZXJzaW9ucyBvZiBBcmNHSVMgUHJvLCBzb21lIGxvY2FsIFItc3F1YXJlcyBhcmUgbmVnYXRpdmUsIHdoaWNoIGlzIG5vdCBwb3NzaWJsZSBpbiBhIHJlZ3Jlc3Npb24gbW9kZWwuIFRoZXJlZm9yZSwgd2UgcmVjb21tZW5kIHVzaW5nIFIgZm9yIEdXUiBhbmFseXNpcyB0byBhdm9pZCB0aGVzZSBsaW1pdGF0aW9ucyBhbmQgdG8gaGF2ZSBtb3JlIGNvbnRyb2wgb3ZlciB0aGUgbW9kZWwgc2VsZWN0aW9uIHByb2Nlc3MuCgoKCgoKIyBSZWZlcmVuY2UKCkFuc2VsaW4sIEwuICgxOTg4KS4gU3BhdGlhbCBlY29ub21ldHJpY3M6IE1ldGhvZHMgYW5kIG1vZGVscy4gS2x1d2VyIEFjYWRlbWljIFB1Ymxpc2hlcnMuCgpBdGtpbnNvbiwgUi4gKDIwMDQpLiBUaGUgZXZpZGVuY2Ugb24gdGhlIGltcGFjdCBvZiBnZW50cmlmaWNhdGlvbjogTmV3IGxlc3NvbnMgZm9yIHRoZSB1cmJhbiByZW5haXNzYW5jZT8gRXVyb3BlYW4gSm91cm5hbCBvZiBIb3VzaW5nIFBvbGljeSwgNCgxKSwgMTA34oCTMTMxLiBodHRwczovL2RvaS5vcmcvMTAuMTA4MC8xNDYxNjcxMDQyMDAwMjE1NDc5CgpCcnVuc2RvbiwgQy4sIEZvdGhlcmluZ2hhbSwgQS4gUy4sICYgQ2hhcmx0b24sIE0uIEUuICgxOTk2KS4gR2VvZ3JhcGhpY2FsbHkgd2VpZ2h0ZWQgcmVncmVzc2lvbjogQSBtZXRob2QgZm9yIGV4cGxvcmluZyBzcGF0aWFsIG5vbnN0YXRpb25hcml0eS4gR2VvZ3JhcGhpY2FsIEFuYWx5c2lzLCAyOCg0KSwgMjgx4oCTMjk4LiBodHRwczovL2RvaS5vcmcvMTAuMTExMS9qLjE1MzgtNDYzMi4xOTk2LnRiMDA5MzYueAoKRnJlZW1hbiwgTC4sICYgQnJhY29uaSwgRi4gKDIwMDQpLiBHZW50cmlmaWNhdGlvbiBhbmQgZGlzcGxhY2VtZW50LiBKb3VybmFsIG9mIHRoZSBBbWVyaWNhbiBQbGFubmluZyBBc3NvY2lhdGlvbiwgNzAoMSksIDM54oCTNTIuIGh0dHBzOi8vZG9pLm9yZy8xMC4xMDgwLzAxOTQ0MzYwNDA4OTc2MzM3CgpHYWxzdGVyLCBHLiBDLiAoMjAwOCkuIFF1YW50aWZ5aW5nIHRoZSBlZmZlY3Qgb2YgbmVpZ2hib3Job29kIGxhbmQgdXNlIGFuZCB6b25pbmcgb24gaG91c2luZyBwcmljZXMuIFJlZ2lvbmFsIFNjaWVuY2UgYW5kIFVyYmFuIEVjb25vbWljcywgMzgoMyksIDI5MeKAkzMwNS4gaHR0cHM6Ly9kb2kub3JnLzEwLjEwMTYvai5yZWdzY2l1cmJlY28uMjAwOC4wMy4wMDMKCkdsYWVzZXIsIEUuIEwuLCAmIEd5b3Vya28sIEouICgyMDE4KS4gUmV0aGlua2luZyBmZWRlcmFsIGhvdXNpbmcgcG9saWN5OiBIb3cgdG8gbWFrZSBob3VzaW5nIHBsZW50aWZ1bCBhbmQgYWZmb3JkYWJsZS4gQW1lcmljYW4gRW50ZXJwcmlzZSBJbnN0aXR1dGUuCgpMZWVzLCBMLiAoMjAwOCkuIEdlbnRyaWZpY2F0aW9uIGFuZCBzb2NpYWwgbWl4aW5nOiBUb3dhcmRzIGFuIGluY2x1c2l2ZSB1cmJhbiByZW5haXNzYW5jZT8gVXJiYW4gU3R1ZGllcywgNDUoMTIpLCAyNDQ54oCTMjQ3MC4gaHR0cHM6Ly9kb2kub3JnLzEwLjExNzcvMDA0MjA5ODAwODA5NzA5OQoKTGVTYWdlLCBKLiwgJiBQYWNlLCBSLiBLLiAoMjAwOSkuIEludHJvZHVjdGlvbiB0byBzcGF0aWFsIGVjb25vbWV0cmljcy4gQ1JDIFByZXNzLgoKTWFsbGFjaCwgQS4gKDIwMTgpLiBUaGUgZGl2aWRlZCBjaXR5OiBQb3ZlcnR5IGFuZCBwcm9zcGVyaXR5IGluIHVyYmFuIEFtZXJpY2EuIElzbGFuZCBQcmVzcy4gaHR0cHM6Ly9kb2kub3JnLzEwLjU4MjIvOTc4LTEtNjEwOTEtNzgxLTAKClRvYmxlciwgVy4gKDE5NzApLiBBIGNvbXB1dGVyIG1vdmllIHNpbXVsYXRpbmcgdXJiYW4gZ3Jvd3RoIGluIHRoZSBEZXRyb2l0IHJlZ2lvbi4gRWNvbm9taWMgR2VvZ3JhcGh5LCA0NiwgMjM04oCTMjQwLiBodHRwczovL2RvaS5vcmcvMTAuMjMwNy8xNDMxNDEK